自己动手写android图片异步载入库

尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44344085

接触android有半年了。关于图片异步载入。一直仅仅用别人的框架,尽管特别方便,可是始终未见识到图片异步载入的庐山真面目。

近期比較悠闲,研究一些高大上的东西。在这篇文章总结一下我对图片异步载入的一些学习心得。

图片载入最重要的无非就是内存和线程。

大家都知道关于内存溢出一般的解决方式就是LruCache,在我的这个demo里我仅仅要使用SoftReference实现了一个缓存类,SoftReference已经被遗弃了,这里仅仅为学习。

代码

com.example.qtdemo_oom.Cache<T, U>

/**
 * 由SoftReference实现的内存缓存<br>
 * 此类仅供学习,因为Android 2.3開始,垃圾回收器倾向于回收软引用和弱引用对象。
 * @author qingtian 
 */
public class Cache<T,U> {

	private Hashtable<T, NewSoftReference> hashTable;// 用于Chche内容的存储
	private ReferenceQueue<U> q;// 垃圾Reference的队列

	/**
	 * 继承SoftReference,使得每个实例都具有可识别的标识。

*/ private class NewSoftReference extends SoftReference<U> { public T key; public NewSoftReference(U em, ReferenceQueue<U> q) { super(em, q); } } /** * 构建一个缓存器实例 */ public Cache() { hashTable = new Hashtable<T, NewSoftReference>(); q = new ReferenceQueue<U>(); } /** * 保存一个实例 * @param t * @param u */ public void put(T t, U u) { cleanCache();// 清除垃圾引用 NewSoftReference ref = new NewSoftReference(u, q); ref.key = t; hashTable.put(t, ref); } /** * 通过uri获取实例 * @param t * @return */ public U get(T t) { U bm = null; if (hashTable.containsKey(t)) { NewSoftReference ref = (NewSoftReference) hashTable.get(t); bm = (U) ref.get(); } return bm; } /** * 在hashTable里里清除已经被回收了的对象的软引用对象 */ @SuppressWarnings("unchecked") private void cleanCache() { NewSoftReference ref = null; while ((ref = (NewSoftReference) q.poll()) != null) { hashTable.remove(ref.key); } } /** * 清除Cache内的所有内容 */ public void clearCache() { cleanCache(); hashTable.clear(); System.gc(); System.runFinalization(); } }


com.example.qtdemo_oom.ImageLoader

/**
 * 图片载入工具类
 * @author qingtian
 */
public class ImageLoader {
	
	private static final String TAG = "qingtian" ;

	//线程池
	ExecutorService threadPool ;
	//自己实现的缓存类
	Cache<String, Bitmap> cache;
	//也能够用v4包提供的缓存
//	LruCache<String, Bitmap> cache;
	
	public ImageLoader() {
		threadPool = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
		cache = new Cache<String, Bitmap>();
//		int maxMemory = (int) Runtime.getRuntime().maxMemory();
//		cache = new LruCache<String, Bitmap>(maxMemory/8){
//			// 測量Bitmap的大小
//			@Override
//			protected int sizeOf(String key, Bitmap value) {
//				return value.getRowBytes() * value.getHeight();
//			}
//		};
	}

	private int currentThreadNum = 0;
	
	class DownBitmapRunnable implements Runnable{
		ImageView iv;  String uri;
		public DownBitmapRunnable( ImageView iv,  String uri) {
			this.iv = iv;
			this.uri = uri;
		}
		@Override
		public void run() {

			currentThreadNum++;
			
			show();

			Bitmap bm = cache.get(uri);
			if (bm == null) {
				Log.i(TAG, "下载");
				bm = BitmapUtil.getImageBitmap(uri);
			}else{
				Log.i(TAG, "不下载");
			}
			if (bm != null) {
				cache.put(uri, bm);
				final Bitmap fBitmap = bm;
				new Handler(Looper.getMainLooper()).post(new Runnable() {

					@Override
					public void run() {
						iv.setImageBitmap(fBitmap);
					}

				});
			}

			currentThreadNum--;
		}
		
	}

	public void show( ImageView iv,  String uri) {

		threadPool.execute(new DownBitmapRunnable(iv, uri));

	}

	public void show() {
		Log.i(TAG, "currentThreadNum:" + currentThreadNum );
	}
}
在这个类里。使用线程池管理线程。避免创建/取消线程时内存的浪费。第14行代码也提供了LruCache代码,我们也能够用LruCache来实现缓存。

代码第54--61行,对于view的操作已经在主线程里了。

com.example.qtdemo_oom.Adapter

public class Adapter extends BaseAdapter {
	public static final String[] uris = new String[] {
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img1b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img2b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img3b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img4b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img5b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img6b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img7b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img8b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img9b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img10b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img11b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img12b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img13b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img14b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img15b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img16b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img17b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img18b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img19b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img20b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img21b.jpg",
			"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img22b.jpg" };

	public LayoutInflater mInflater;
	public ImageLoader loader;

	public Adapter(Context context) {
		mInflater = LayoutInflater.from(context);
		loader = new ImageLoader();
	}

	@Override
	public int getCount() {
		return uris.length;
	}

	@Override
	public Object getItem(int arg0) {
		return uris[arg0];
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		ViewHolder holder = null;
		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.item, null);

			holder = new ViewHolder();
			holder.tv = (TextView) convertView.findViewById(R.id.tv);
			holder.iv = (ImageView) convertView.findViewById(R.id.iv);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		holder.tv.setText((String) getItem(position));

		loader.show(holder.iv, uris[position]);

		return convertView;
	}

	class ViewHolder {
		TextView tv;
		ImageView iv;
	}

}

代码第66行,就能够异步载入图片了。


com.example.qtdemo_oom.util.BitmapUtil

public class BitmapUtil {
	
	public static Bitmap getImageBitmap(String uri) {
		URL imgUrl = null;
		Bitmap bitmap = null;
		InputStream is = null;
		try {
			imgUrl = new URL(uri);
			HttpURLConnection conn = (HttpURLConnection) imgUrl
					.openConnection();
			conn.setDoInput(true);
			conn.connect();
			is = conn.getInputStream();
			bitmap = BitmapFactory.decodeStream(is);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
					is = null;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return bitmap;
	}
	
}
通过这个简单的demo,我见到了内存缓存的真面目。也学习了LruCache的源代码(这里没体现)。

当然这是我学习异步图片载入的第一版,希望在后面的版本号里写的更成熟。

源代码下载

原文地址:https://www.cnblogs.com/gccbuaa/p/6767236.html