標籤:非同步載入圖片 線程池 lrucache softreference
尊重他人勞動成果,轉載請說明出處: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;}@Overridepublic 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() {@Overridepublic 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();}@Overridepublic int getCount() {return uris.length;}@Overridepublic Object getItem(int arg0) {return uris[arg0];}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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的源碼(這裡沒體現)。當然這是我學習非同步圖片載入的第一版,希望在後面的版本裡寫的更成熟。
源碼下載
自己動手寫android圖片非同步載入庫