場景
想象一下加載圖片的時候,ImageView首先設置一個placeHolder,然後開啟AsyncTask去加載合適的圖片,圖片加載成功之後, 怎麼去更新ImageView?一般來講,有兩種處理方式,第一種:將ImageView傳遞給AsyncTask,task執行完之後,直接ImageView設置bitmap,第二種:Task執行完畢之後,將Bitmap存儲在緩存裡,通知主線程的view,進行數據更新。
將ImageView傳遞給AsyncTask
要求
ListView或者GridView會復用ImageView,例如pos為4的ImageView4開啟了一個AsyncTask,用戶滾動到了pos為8的位置,復用了ImageView4,即使這個時候AsyncTask更新完了,但是也不能去更新ImageView4。
AsyncTask不能阻止ImageView的內存釋放,例如當用戶離開這個頁面的時候,應該銷毀界面,AsyncTask應當避免造成內存洩露
AsyncTask執行完畢之後,應該能夠拿到ImageView,並且ImageView設置Bitmap之前需要判斷ImageView與Drawable和Task之間必須一一對應
實現
BitmapWorkerTask繼承AsyncTask,弱引用ImageView,這樣AsyncTask既可以在執行完畢之後取到ImageView更新Bitmap,又不會阻止ImageView被釋放
ImageView每次都會設置一個placeHolder AsyncDrawable,在AsyncDrawable中弱引用AsyncTask,當AsyncTask執行完畢,可以通過ImageView get AsyncDrawable,然後通過AsyncDrawable獲取到BitmapTask,判斷task是否是同一個task,如果是,那麼就能確定ImageView,AsyncDrawable,AsyncTask一一對應,可以進行數據更新,此外AsyncTask完全執行完畢之後,也可以直接被釋放掉了,AsyncDrawable不會阻礙AsyncTask被釋放
Task執行完畢之後,將Bitmap存儲在緩存裡,通知主線程的view,進行數據更新
缺點:
盲目刷新,效率太低,特別是ImageView特別多,AsyncTask執行很快,那麼刷新的頻率會特別高,這樣會導致頁面不斷刷新,甚至卡頓
總結
ImageView,BitmapWorkerTask,AsyncDrawable的關系
BitmapWorkerTask持有一個WeakReference imageViewReference,弱引用ImageView,用作異步處理加載圖片的任務。
AsyncDrawable巧妙的引用持有弱引用WeakReference bitmapWorkerTaskReference,AsyncDrawable繼承自BitmapDrawable,這樣ImageView就可以setImageBitmap(AsyncDrawable)
AsyncDrawable中弱引用BitmapWorkerTask,ImageView.getDrawable又可以獲得AsyncDrawable,繼而獲得BitmapWorkerTask
關鍵代碼
protected static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference =
new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
protected class BitmapWorkerTask extends AsyncTask<Object, Void, BitmapDrawable> {
private Object data;
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
final AsyncDrawable asyncDrawable =
new AsyncDrawable(mResources, map, task);
imageView.setImageDrawable(asyncDrawable);
protected void onPostExecute(BitmapDrawable value) {
final ImageView imageView = getAttachedImageView();
if (value != null && imageView != null) {
imageView.setImageDrawable(value);
afterGetBitmap(imageView, value);
}
}