ListView中类似于微信朋友圈功能刷新的使用二

这是对上一篇blog的改进:主要有:增加一个内存缓存,首先ListVIew现在内存缓存中去寻找图片,不存在,再去本地缓存目录去寻找,不存在再去网上下载。然后,对于图片进行压缩,我们从网上或者内存中,读取出来的图片,他的分辨率等会比较高,我们不需要那么高的图片质量就可以了,所以我对图片进行了压缩,然后对缓存目录做了优化,当SD卡不存在的时候,则把缓存图片保存到手机自带的空间,存在则保存把SD卡。然后更新ImageView是利用Ui线程提供的一个方法,runOnUiThread去更新UI,大家可以以通过handle去更新也行。增加一些文件操作类。

下面请看代码:

MainActivity.java

public class MainActivity extends Activity
{
	private static ListView myListView;
	private static View footer;
	private static MyListViewAdapter adapter;
	private static boolean flag = true;
	private static Context context;
	public static final int OK = 1;//首次加载成功发送的信号
	public static final int ERROR = -1;//下载失败的信号
	public static final int YES = 2;//下拉时候加载成功的信号
	/* 第一个路径是用于初次加载,第二个路径是用于下拉刷新 */
	public static final String[] paths =
	{ "http://10.10.117.197:8080/web/mylist1.xml", "http://10.10.117.197:8080/web/mylist2.xml" };

	private static Handler mHandler = new Handler()
	{
		@SuppressWarnings("unchecked")
		public void handleMessage(android.os.Message msg)
		{
			if (msg.what == OK)// 用于首次下载数据成功之后绑定数据和适配器,以及listview
			{
				List<Picture> data = (List<Picture>) msg.obj;
				myListView.addFooterView(footer);
				adapter = new MyListViewAdapter(data, R.layout.listview_item, context);
				myListView.setAdapter(adapter);
				myListView.removeFooterView(footer);// 首次加载不用显式footer
			} else if (msg.what == YES)
			{
				flag = true;
				adapter.setDate((List<Picture>) msg.obj);
				adapter.notifyDataSetChanged();
				if (myListView.getFooterViewsCount() > 0)
				{
					myListView.removeFooterView(footer);
				}
			} else
			{
				Toast.makeText(context, "请检查网络", Toast.LENGTH_SHORT).show();
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		context = this;
		setContentView(R.layout.activity_main);
		myListView = (ListView) this.findViewById(R.id.my_listview);
		footer = getLayoutInflater().inflate(R.layout.footer, null);
		myListView.setOnScrollListener(new ListViewScrollListener());
		new LoadingDataThread(mHandler, paths[0], OK).start();
	}

	class ListViewScrollListener implements OnScrollListener
	{
		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState)
		{
			if (adapter != null)
			{
				switch (scrollState) {
				case OnScrollListener.SCROLL_STATE_FLING://由于惯性listview任然在滚动
					adapter.setFlagBusy(true);
					break;
				case OnScrollListener.SCROLL_STATE_IDLE://不再滚动
					adapter.setFlagBusy(false);
					break;
				case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://用户触摸着屏幕
					adapter.setFlagBusy(false);
					break;
				default:
					break;
				}
				adapter.notifyDataSetChanged();
			}
		}

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
		{
			if (adapter != null)
			{
				int lastVisiableItem = myListView.getLastVisiblePosition();
				if (totalItemCount == lastVisiableItem + 1 && totalItemCount > 0)
				{
					if (flag)
					{
						flag = false;
						myListView.addFooterView(footer);
						new LoadingDataThread(mHandler, paths[1], YES).start();
						// 下载新的数据
					}
				}
			}
		}
	}

	// 用户 退出时删除缓存
	@Override
	protected void onDestroy()
	{
		ImageViewLoader imageLoader = adapter.getLoader();// 获取一个loader,删除缓存
		if (imageLoader != null)
		{
			imageLoader.clearCache();// 清楚缓存
		}
		super.onDestroy();
	}
}

/**
 * 完成xml数据的下载,包括首次下载和以后每一次需要的下载
 *
 * @author Administrator 黎伟杰
 *
 */
class LoadingDataThread extends Thread
{
	private Handler UIHnalder;
	private List<Picture> data = new ArrayList<Picture>();
	private String path;
	private int code;

	public LoadingDataThread (Handler mHandler , String path , int code)
	{
		this.UIHnalder = mHandler;
		this.path = path;
		this.code = code;
	}

	@Override
	public void run()
	{
		data.addAll(ListViewService.getData(path));// 得到数据并且通过Handler返回,更新适配器绑定的数据
		if (data.size() > 0)
		{
			if (code == MainActivity.YES)
			{
				try
				{
					Thread.sleep(2000);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}
			Message msg = Message.obtain();
			msg.what = code;// 根据不同的what发送给handler进行不同的处理
			msg.obj = data;
			UIHnalder.sendMessage(msg);// 发送数据
		} else
		{
			UIHnalder.sendEmptyMessage(MainActivity.ERROR);
		}
	}
}

MyListAdapter.java

/**
 * 适配器类
 * 运行在UI线程中
 * @author Administrator
 *
 */
public class MyListViewAdapter extends BaseAdapter
{
	private List<Picture> data = new ArrayList<Picture>();// 数据
	private int listviewItem;// listview显示条目的id
	private LayoutInflater inflater;// 加载layout器
	private ImageViewLoader loader;// 图片下载器

	private boolean mBusy = false;//当ListView不存在惯性的时为true,用户拖动或者没有触摸屏幕为false

	public void setFlagBusy(boolean busy) {
		this.mBusy = busy;
	}
	// 添加新的数据到adapter中
	public void setDate(List<Picture> data)
	{
		this.data.addAll(data);
	}

	/**
	 * @return the loader
	 */
	public ImageViewLoader getLoader()
	{
		return loader;
	}

	public MyListViewAdapter (List<Picture> data , int listviewItem , Context context)
	{
		this.data.addAll(data);
		this.listviewItem = listviewItem;
		inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		loader = new ImageViewLoader(context);
	}

	public int getCount()
	{
		return data.size();
	}

	public Object getItem(int position)
	{
		return data.get(position);
	}

	@Override
	public long getItemId(int position)
	{
		return position;
	}

	public View getView(int position, View convertView, ViewGroup parent)
	{
		ViewHolder holder = null;
		if (convertView == null)
		{
			holder = new ViewHolder();
			convertView = inflater.inflate(listviewItem, null);
			holder.imageview = (ImageView) convertView.findViewById(R.id.iv_image);
			holder.textView = (TextView) convertView.findViewById(R.id.tv_tips);
			convertView.setTag(holder);
		} else
		{
			holder = (ViewHolder) convertView.getTag();
		}
		Picture picture = data.get(position);
		if (!mBusy) {
			loader.DisplayImage(picture.getPath(), holder.imageview, false);
			holder.textView.setText(picture.getName()+"--" + position+ "--IDLE ||TOUCH_SCROLL");
		} else {
			loader.DisplayImage(picture.getPath(), holder.imageview, false);
			holder.textView.setText("--" + picture.getName()+"--FLING"+position );
		}
		return convertView;
	}

	// holder类,
	static class ViewHolder
	{
		ImageView imageview;
		TextView textView;
	}
}

ListService.java

public class ListViewService
{

	public static List<Picture> getData(String path)
	{
		// 192.168.1.109
		try
		{
			HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
			conn.setConnectTimeout(5000);
			conn.setRequestMethod("GET");
			if(200 == conn.getResponseCode())
			{
				return parserXML(conn.getInputStream());
			}
		} catch (IOException e)
		{
			e.printStackTrace();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}

	private static List<Picture> parserXML(InputStream inputStream) throws Exception
	{
		List<Picture> data = new ArrayList<Picture>();
		Picture picture = null;
		XmlPullParser parser = Xml.newPullParser();
		parser.setInput(inputStream,"UTF-8");
		int event = parser.getEventType();
		while(XmlPullParser.END_DOCUMENT != event)
		{
			switch (event)
			{
			case XmlPullParser.START_TAG:
				if("image".equals(parser.getName()))
				{
					picture = new Picture();
					picture.setName(parser.getAttributeValue(0));
					break;
				}
				if("path".equals(parser.getName()))
				{
					picture.setPath(parser.nextText());
					break;
				}
				break;

			case XmlPullParser.END_TAG:
				if("image".equals(parser.getName()))
				{
					data.add(picture);
					picture = null;
				}
				break;
			}
			event = parser.next();
		}
		System.out.println(data.size());
		return data;
	}

}

这三个类跟之前的功能差不多,代码也是,只是现在我们利用了ImageView去下载并且维护ImageView的更新

下面是新的重要代码:

ImageViewLoader.java,他的功能,利用线程池去下载维护图片,并且更新ImageVIew,分别利用内存缓存图片和本地缓存图片

/**
 * 图片下载,运行在UI线程
 * @author Administrator
 *
 */
public class ImageViewLoader
{
	private MemoryCache memoryCache = new MemoryCache();// 内存缓存
	private FileCache fileCache;// 文件缓存
	// 以弱键 实现的基于哈希表的 Map,在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。
	// 更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。
	// 丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所不同。
	private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
	// 线程池
	private ExecutorService executorService;

	public ImageViewLoader (Context context)
	{
		fileCache = new FileCache(context);
		executorService = Executors.newFixedThreadPool(5);// 最大线程数量
	}

	/**
	 * 下载图片准备类
	 * @param url 下载路径
	 * @param imageview 显示组件
	 */
	public void DisplayImage(String url, ImageView imageview, boolean isLoadOnlyFromCache)
	{
		imageViews.put(imageview, url);

		Bitmap bitmap = memoryCache.get(url);

		if (bitmap != null)
		{
			imageview.setImageBitmap(bitmap);// 缓存中存在该bitmap,返回,否则下载
		} else if(!isLoadOnlyFromCache)
		{
			queuePhoto(imageview, url);//不存在与内存的缓存中,则取下文件中查找或者下载
		}

	}

	/**
	 * 防止图片错位
	 * @param photoToLoad
	 * @return
	 */
	private boolean imageViewReused(PhotoToLoad photoToLoad)
	{
		String tag = imageViews.get(photoToLoad.imageView);
		if (tag == null || !tag.equals(photoToLoad.url))
			return true;
		return false;
	}

	/**
	 * 下载图片
	 * @param url 路径
	 * @param imageView 需要显示该图片的ImageView组件
	 */
	private void queuePhoto(ImageView imageview, String url)
	{
		PhotoToLoad p = new PhotoToLoad(url, imageview);
		// 每一张需要下载的图片都需要提交给线程池处理,他的最大同时能运行的线程数是5,多余这个数目后来的线程会处于等待状态
		executorService.submit(new PhotosLoader(p));
	}

	/**
	 * 真正下载图片的方法,
	 *
	 * @param url
	 *            返回一个经过压缩之后的bitmap
	 * @return
	 */
	private Bitmap getBitmap(String url)
	{
		File f = fileCache.getFile(url);// 查看缓存文件是否存在,存在去压缩,之后返回,不存在则取下载并且保存在SD卡目录中
		Bitmap b = null;
		if (f != null && f.exists())
		{
			b = decodeFile(f);
			return b;
		}
		InputStream is = null;
		FileOutputStream fos = null;
		try
		{
			URL imageUrl = new URL(url);// 从网络下载图片
			HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
			conn.setConnectTimeout(3000);
			conn.setReadTimeout(3000);
			conn.setRequestMethod("GET");
			if (200 == conn.getResponseCode())
			{
				is = conn.getInputStream();
				fos = new FileOutputStream(f);//下载图片到缓存目录
				int len;
				byte[] buffer = new byte[1024];
				while ((len = is.read(buffer)) != -1)
				{
					fos.write(buffer, 0, len);
				}
				b = decodeFile(f);//压缩图片
				return b;
			}
		} catch (MalformedURLException e)
		{
			e.printStackTrace();
		} catch (ProtocolException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		} finally
		{
			if (is != null)
			{
				try
				{
					is.close();
				} catch (IOException e)
				{
					e.printStackTrace();
				}
			}
			if(fos != null)
			{
				try
				{
					fos.close();
				} catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 对图片进行压缩
	 * @param f 需要压缩的图片
	 * @return
	 */
	private Bitmap decodeFile(File f)
	{
		try
		{
			BitmapFactory.Options o = new BitmapFactory.Options();// 获取一个option对象
			o.inJustDecodeBounds = true;//设置不显示实际的bitmap,获得他的实际宽和高
			BitmapFactory.decodeStream(new FileInputStream(f), null, o);
			final int REQUIRED_SIZE = 100;//需要显示的大小,应该是小与等于200(宽或者是高)
			int width_tmp = o.outWidth;
			int height_tmp = o.outHeight;
			System.out.println("width_tmp="+width_tmp+"height_tmp="+height_tmp);
			int scale = 1;
			while (true)
			{
				if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
				{
					break;
				}
				width_tmp /= 2;//进行压缩
				height_tmp /= 2;
				scale *= 2;
			}
			o.inJustDecodeBounds = false;//设置显示
			o.inSampleSize = scale;
			return BitmapFactory.decodeStream(new FileInputStream(f), null, o);

		} catch (FileNotFoundException e)
		{
			System.out.println("压缩失败");
		}
		return null;
	}

	public void clearCache()
	{
		memoryCache.clear();
		fileCache.clear();
	}

	/**
	 * 实际更新ImageView的类
	 * @author Administrator
	 *
	 */
	class BitmapDisplayer implements Runnable
	{
		Bitmap bmp;
		PhotoToLoad photoToLoad;

		public BitmapDisplayer (Bitmap bmp , PhotoToLoad photoToLoad)
		{
			this.bmp = bmp;
			this.photoToLoad = photoToLoad;
		}

		@Override
		public void run()
		{
			if (imageViewReused(photoToLoad))
			{
				return;
			}
			if (bmp != null)
			{
				photoToLoad.imageView.setImageBitmap(bmp);
			}
		}
	}

	private class PhotoToLoad
	{
		public String url;
		public ImageView imageView;

		public PhotoToLoad (String url , ImageView iamgeView)
		{
			this.url = url;
			this.imageView = iamgeView;
		}
	}

	/**
	 * 图片真正下载管理类类
	 * @author Administrator
	 *
	 */
	class PhotosLoader implements Runnable
	{
		PhotoToLoad photoToLoad;

		public PhotosLoader (PhotoToLoad photoToLoad)
		{
			this.photoToLoad = photoToLoad;
		}

		@Override
		public void run()
		{
			if (imageViewReused(photoToLoad))
			{
				return;
			}

			Bitmap bmp = getBitmap(photoToLoad.url);
			memoryCache.put(photoToLoad.url, bmp);// 添加到内存的缓存中
			if (imageViewReused(photoToLoad))
			{
				return;
			}
			BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
			Activity a = (Activity) photoToLoad.imageView.getContext();//更新UI,这里使用时UI线程中利用runOnUiThread方法更新,这里去的上下文
			a.runOnUiThread(bd);
		}
	}

}

内存缓存类:

MemoryCache.java

/**
 * 内存缓存处理类
 * @author Administrator
 *
 */
public class MemoryCache
{
	// 放入缓存时是个同步操作,线程安全
	// LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU
	// 这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率
	private Map<String, Bitmap> cache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));
	// 缓存中图片所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存
	private long size = 0;// current allocated size
	// 缓存只能占用的最大堆内存
	private long limit = 1000000;// max memory in bytes,最大允许的内存缓存,自己随意设定,需要合适

	public MemoryCache()
	{
		// use 25% of available heap size
		setLimit(Runtime.getRuntime().maxMemory() / 10);// 返回当前最大可用内存整除10
	}

	public void setLimit(long new_limit)
	{
		limit = new_limit;
	}

	public Bitmap get(String id)
	{
		try
		{
			if (!cache.containsKey(id))// 如果不包含该uri对于的图片,则返回null
				return null;
			return cache.get(id);// 存在则返回该图片
		} catch (NullPointerException ex)
		{
			return null;
		}
	}

	public void put(String uri, Bitmap bitmap)
	{
		try
		{
			if (cache.containsKey(uri))// 假如已经包含了该uri的图片,则size应该不用增加,所以先减去该长度,添加进去之后在加上,假如不存在则把他的长度添加到size中
				size -= getSizeInBytes(cache.get(uri));
			cache.put(uri, bitmap);
			size += getSizeInBytes(bitmap);
			checkSize();
		} catch (Throwable th)
		{
			th.printStackTrace();
		}
	}

	/**
	 * 严格控制堆内存,如果超过将首先替换最近最少使用的那个图片缓存
	 *
	 */
	private void checkSize()
	{
		if (size > limit)
		{
			// 先遍历最近最少使用的元素
			Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();
			while (iter.hasNext())
			{
				Entry<String, Bitmap> entry = iter.next();
				size -= getSizeInBytes(entry.getValue());
				iter.remove();
				if (size <= limit)
					break;
			}
		}
	}

	public void clear()
	{
		cache.clear();// 把内存中的cache去掉,相当于把data去掉
	}

	/**
	 * 图片占用的内存
	 * @return bitmap占用的字节数
	 */
	long getSizeInBytes(Bitmap bitmap)
	{
		if (bitmap == null)
			return 0;
		return bitmap.getRowBytes() * bitmap.getHeight();
	}
}

图片本地缓存:

FileCache.java

/**
 * 图片本地缓存
 * @author Administrator
 *
 */
public class FileCache
{
	private String dir;

	public FileCache (Context context)
	{
		dir = getCahceDir();
		createDirectory(dir);
	}

	/**
	 * 获取文件保存路径,包括文件名称
	 * @param uri
	 * @return
	 */
	public String getSavePath(String uri)
	{
		String fileName = String.valueOf(uri.hashCode());
		return getCahceDir() + fileName;
	}

	/**
	 *  返回文件名称,包含路径,
	 * @param uri
	 * @return
	 */
	public File getFile(String uri)
	{
		File file = new File(getSavePath(uri));
		return file;
	}

	/**
	 * 获得保存缓存图片的目录
	 * @return
	 */
	public String getCahceDir()
	{
		return FileManager.getSaveFilePath();
	}

	public void clear()
	{
		deleteDirectory(dir);
	}

	public static boolean createDirectory(String filePath){
		if (null == filePath) {
			return false;
		}

		File file = new File(filePath);

		if (file.exists()){
			return true;
		}

		return file.mkdirs();

	}

	/**
	 * 删除保存本地的图片
	 * @param dir 目录
	 * @return 是否成功
	 */
	public boolean deleteDirectory(String dir)
	{
		if (null == dir) {
			System.out.println("Invalid param. dir: " + dir);
			return false;
		}

		File file = new File(dir);

		if (file == null || !file.exists()) {
			return false;
		}

		if (file.isDirectory()) {
			File[] list = file.listFiles();

			for (int i = 0; i < list.length; i++) {
				System.out.println("delete dir: " + list[i].getAbsolutePath());
				if (list[i].isDirectory()) {
					deleteDirectory(list[i].getAbsolutePath());
				} else {
					list[i].delete();
				}
			}
		}

		System.out.println("delete dir: " + file.getAbsolutePath());
		file.delete();
		return true;
	}
}

缓存文件管理类;

FileManager.java

/**
 * 缓存文件管理
 * @author Administrator
 *
 */
public class FileManager
{

	public static String getSaveFilePath()
	{
		if (hasSDCard()) {
			return getRootFilePath() + "liweijie/files/";//存在SD卡的时候,则保存到SD卡
		} else {
			return getRootFilePath() + "liweijie/files";//不存在SD卡保存到手机
		}
	}
	public static String getRootFilePath()
	{
		if (hasSDCard())
		{
			return Environment.getExternalStorageDirectory().getAbsolutePath() + "/";// filePath:/sdcard/,有内存卡
		} else
		{
			return Environment.getDataDirectory().getAbsolutePath() + "/data/"; // filePath:
		}
	}
	/**
	 * sd卡是否处于可读可写状态
	 * @return
	 */
	public static boolean hasSDCard()
	{
		String status = Environment.getExternalStorageState();
		if (!status.equals(Environment.MEDIA_MOUNTED))
		{// 内存卡可读可写
			return false;
		}
		return true;
	}
}

domain类

Pisture.java

/**
 * domain类 包含属性的get和set方法
 * @author Administrator
 *
 */
public class Picture
{
	private String name;
	private String path;

	public Picture ()
	{
	}

	public Picture (String name , String path)
	{
		super();
		this.name = name;
		this.path = path;
	}

	/**
	 * @return the name
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name)
	{
		this.name = name;
	}

	/**
	 * @return the path
	 */
	public String getPath()
	{
		return path;
	}

	/**
	 * @param path
	 *            the path to set
	 */
	public void setPath(String path)
	{
		this.path = path;
	}
}

请求的xml数据格式:

<?xml version="1.0" encoding="UTF-8"?>
<contacts>
	<contact id="1">
 		<name>张飞</name>
 		<image src="http://10.10.117.197:8080/web/images/1.gif"/>
	</contact>
	<contact id="2">
 		<name>黎伟杰</name>
 		<image src="http://10.10.117.197:8080/web/images/2.gif"/>
	</contact>
	<contact id="3">
 		<name>黎AA</name>
 		<image src="http://10.10.117.197:8080/web/images/3.gif"/>
	</contact>
	<contact id="4">
 		<name>黎BB</name>
 		<image src="http://10.10.117.197:8080/web/images/4.gif"/>
	</contact>
	<contact id="5">
 		<name>黎CC</name>
 		<image src="http://10.10.117.197:8080/web/images/5.gif"/>
	</contact>
	<contact id="6">
 		<name>黎DD</name>
 		<image src="http://10.10.117.197:8080/web/images/6.gif"/>
	</contact>
	<contact id="7">
 		<name>黎EE</name>
 		<image src="http://10.10.117.197:8080/web/images/7.gif"/>
	</contact>
	<contact id="8">
 		<name>黎FF</name>
 		<image src="http://10.10.117.197:8080/web/images/8.gif"/>
	</contact>
	<contact id="9">
 		<name>黎GG</name>
 		<image src="http://10.10.117.197:8080/web/images/9.gif"/>
	</contact>
	<contact id="10">
 		<name>黎HH</name>
 		<image src="http://10.10.117.197:8080/web/images/10.gif"/>
	</contact>
</contacts>

关于ListView以及界面布局文件就不贴出来了,还有footer的也是,大家使用的时候记得加上权限。

结果截图:

时间: 2024-12-09 09:18:45

ListView中类似于微信朋友圈功能刷新的使用二的相关文章

ListView中类似于微信朋友圈功能刷新的使用

这一篇blog是接着上一篇,上一篇有一些不完美,这里做出改进. 首先我们需要理清思路:使用ListView显示数据是很方便的,ListVIew的数据之间通过适配器adapter去作为桥梁连接起来.当我们需要使用listview显示大量数据的时候,我们需要使用到分页功能,比如我们有一千条数据,那么我们应该分开数据一点一点的显示,比如每次用户刷新我就增加20条数据额.展示给用户,每次都是增加一定量的数据给用户,直到数据没有为止.为了改善用户体验,我们还应该把上一次用户退出的时候显示最新的20条数据保

第三方应用分享到微信朋友圈功能

分享自http://blog.csdn.net/qianfu111/article/details/9115303 最权威的学习资料还是要去看官网,以及官网提供的Demo,基本上你是可以直接拿来使用的,这是官网网站:http://open.weixin.qq.com/. 在微信分享中主要碰到了如下问题:第一次可以分享,以后就无法调用出分享对话框.这不是程序问题,而是需要提交审核,只有审核通过,才可以调出分享对话框.不相信?那你可以先将微信退出,再试着点击分享,这时就会弹出登录对话款,登完之后也没

实现类似微信朋友圈功能(一 )只供自己好友可见的点赞和评论

先来看看功能的需求 跟微信朋友圈一样的功能. 我是分步骤做: 1:先查看朋友圈.查看的都是自己的好友.点赞和评论是好友才能看见.不是好友就隐藏看下图.三个不用的用户登录 在展示的接口我先查询出当前好友的点赞和评论的用户集合. doctorId = inputFields.doctorId; //当前医生人 partyIds.add(doctorId); andExprs = FastList.newInstance(); andExprs.add(EntityCondition.makeCond

实现类似微信朋友圈功能(二)点赞推送给自己的好友或关注

需求:评论点赞通知跟自己是好友或关注的评论点赞该条说说的人 这个功能是点赞和评论接口,在点赞的同时会给自己的朋友 (是在该条说说有联系的 评论或点赞)进行消息推送 还是跟上一个一样进行筛选.相同的进行推送.在完成之后感觉有问题.就是出现在推送哪里.微信的是 点赞 推送.取消点赞.但是推送还在.在点赞的情况下.消息不会重复,始终保证数据的唯一性. 而我这个是没有做处理.在取消的时候,消息不会进行删除.重新点赞的情况下,消息会重复添加.也就造成了.其实只有一个推送.却出现很多条数据. 当然解决起来其

如何在App中实现朋友圈功能之一朋友圈实现原理浅析——箭扣科技Arrownock

如何在App中实现朋友圈功能 之一 朋友圈实现原理浅析 微信朋友圈.新浪微博.知乎等知名朋友圈类型功能,大家有没有想过其实现的逻辑呢? 本文以微信朋友圈功能为例,解析实现逻辑. 朋友圈的结构: 朋友圈从总体上来说会分为6块结构,分别是墙.用户.图片.墙贴.评论与点赞. 墙:一块公共的墙,所有的墙贴都位于其上,如果APP只实现朋友圈功能,那么墙贴其实是可以不用的,但是如果APP要实现朋友圈.新闻圈等等其他各种墙贴类型消息的话,那么墙就显得很有必要了,这时候我们需要通过建立不同的墙来展示不同类型的墙

Android&quot;挂逼&quot;修炼之行---微信实现本地视频发布到朋友圈功能

一.前言 前一篇文章已经详细介绍了如何使用Xposed框架编写第一个微信插件:摇骰子和猜拳作弊器  本文继续来介绍如何使用Xposed框架编写第二个微信插件,可以将本地小视频发布到朋友圈的功能.在这之前我们还是要有老套路,准备工作要做好,这里还是使用微信6.3.9版本进行操作,准备工作: 1.使用apktool工具进行反编译,微信没有做加固防护,所以这个版本的微信包反编译是没有任何问题的. 2.借助于可视化反编译工具Jadx打开微信包,后续几乎重要分析都是借助这个工具来操作的. 二.猜想与假设

andriod 实现新浪、QQ空间、微信朋友圈、微信好友分享功能

前言:自己在学习的过程中的一些操作过程,对分享的一些理解.下面就讲解一下: 下载地址:http://download.csdn.net/detail/u014608640/7490357 首先,我们需要去ShareSdk官方网站http://sharesdk.cn/ 去下载ShareSDK ,然后我们会有4个文件: 根据我自己在学习的过程中只用到了第一个文件夹的 libs目录的2个项目,这2个是必须要的,是ShareSdk提供的,然后需要将这2个放入到自己做的项目当中去,在Res目录下有一个 S

iOS开发——项目实战总结&amp;类微信朋友圈发动态功能初步-图片与视频上传

类微信朋友圈发动态功能初步-图片与视频上传 最近在做一个新的项目,涉及到了关于图片和视频上传和显示的功能,研究了一段时间,总结一下. 使用AFNetworking上传图片(可一次上传多张图片,包含不同类型png, jpeg)和视频 1 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 2 3 AFHTTPRequestOperation *operation = [manager P

iOS微信朋友圈 评论点击姓名功能 (补充)

如果要做成微信朋友圈的评论效果, 那么评论用一个UITableview去加载,每个UITableviewCell上加载一个PPLabel. 但是这样会导致一个问题,PPLable在响应点击单词的时候,同样UITableviewCell会响应select事件. 有两种处理办法: 1.截取点击事件,这种办法比较复杂,需要了解iOS的事件传递机制.由于PPLable在事件响应的最底层,而我们需要在PPLable中判断了是否点击到单词,才能决定UITableviewCell是否响应点击事件,这样的做法过