Android异步加载图片(一)下载完图片之后,如何更新界面

场景

想象一下加载图片的时候,ImageView首先设置一个placeHolder,然后开启AsyncTask去加载合适的图片,图片加载成功之后, 怎么去更新ImageView?一般来讲,有两种处理方式,第一种:将ImageView传递给AsyncTask,task执行完之后,直接ImageView设置bitmap,第二种:Task执行完毕之后,将Bitmap存储在缓存里,通知主线程的view,进行数据更新。

将ImageView传递给AsyncTask

要求

  1. ListView或者GridView会复用ImageView,例如pos为4的ImageView4开启了一个AsyncTask,用户滚动到了pos为8的位置,复用了ImageView4,即使这个时候AsyncTask更新完了,但是也不能去更新ImageView4。
  2. AsyncTask不能阻止ImageView的内存释放,例如当用户离开这个页面的时候,应该销毁界面,AsyncTask应当避免造成内存泄露
  3. 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);
        }
    }
posted @ 2015-03-02 20:08  AndroidGrass  阅读(1733)  评论(0编辑  收藏  举报