zoukankan      html  css  js  c++  java
  • Android图片异步加载的方法

        很多时候,我们在加载大图片或者需要处理较多图像数据的时候,希望显示效果能好点,不至于因为图片解码耗时产生ANR等情况,不得不说异步加载是个不错的方法。说到异步加载,避免application出现ANR情况,我们一般都是另起线程,不占用Main Thread,这样就能避免ANR情况产生。常用的异步方法有:AsyncTask,HandlerThread,Activity.runOnUIThread(Runnable)等。本文介绍的大图片异步加载使用的就是AsyncTask来实现的。

        先定义一个ImageView对象image,该对象就是我们最终要显示的图片。简化我们获取图片的过程,这里用resource id即放在drawable下的图片mActualImageId为例,当然,我们也可以从网络上下载或者设定选定SD卡中的某张图片。图片未真正解码获取之前,我们用加载图片显示mLoadingImage。

        第一步:创建AsyncTask

        private class BitmapWorkerTask extends AsyncTask<Integer, Void, BitmapDrawable> {
            private int mResId;
            private final WeakReference<ImageView> imageViewReference;
    
            public BitmapWorkerTask(ImageView imageView) {
                imageViewReference = new WeakReference<ImageView>(imageView);
            }
    
            /**
             * Background processing.
             */
            @Override
            protected BitmapDrawable doInBackground(Integer... params) {
                Log.d(TAG, "doInBackground - starting work");
                
                mResId = params[0].intValue();
                Bitmap bitmap = null;
                BitmapDrawable drawable = null;
    
                Log.d(TAG, "doInBackground - mResId = " + mResId);
                if (bitmap == null) {
                	bitmap = processBitmap(mResId);
                }
                
                if (bitmap != null) {
                    // Running on Honeycomb or newer, so wrap in a standard BitmapDrawable
                    drawable = new BitmapDrawable(mResource, bitmap);
                }
    
                Log.d(TAG, "doInBackground - finished work");
                return drawable;
            }
            
            /**
             * Once the image is processed, associates it to the imageView
             */
            @Override
            protected void onPostExecute(BitmapDrawable value) {
                // if cancel was called on this task or the "exit early" flag is set then we're done
                final ImageView imageView = getAttachedImageView();
                if (value != null && imageView != null) {
                    Log.d(TAG, "onPostExecute - setting bitmap");
                    if (mProgress != null) {
                    	mProgress.setVisibility(View.GONE);
                    }
                    
                    setImageDrawable(imageView, value);
                }
            }
            
            private ImageView getAttachedImageView() {
                final ImageView imageView = imageViewReference.get();
                final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
    
                if (this == bitmapWorkerTask) {
                    return imageView;
                }
    
                return null;
            }
        }

    从上面代码看,processBitmap就是在做图片解码的动作,如果对resource id做解码,使用BitmapFactory.decodeResource。如果对图片文件解码,使用BitmapFactory.decodeFile。还有一种使用BitmapFactory.decodeFileDescriptor解码。结果都是返回解码后的Bitmap,创建得到drawable对象并传给主线程,在onPostExecute中用ImageView的接口函数setImageDrawable接口将最终图片显示内容显示出来。

    第二步:创建异步drawable对象

    先看我们创建的异步drawable对象是什么?

        private 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();
            }
        }


    该类很重要的一个成员是弱引用bitmapWorkerTaskReference,在内存不足的情况下,弱引用指向的数据会被系统回收,这样就不会因系统内存不足,长时间等待而引起ANR。注意到构造函数实际上会调用super(res, bitmap),我们这个类继承自BitmapDrawable,如果撇开弱引用不管,这个类实际上就是BitmapDrawable。

    好,铺垫了这么多,异步加载的方法下面可以展开了。

    第三步:异步加载图片

    	public void loadImage(int resId, ImageView image) {
    		if (image == null) {
    			return ;
    		}
    		
    		mActualImageId = resId;
    		mAsyncTask = new BitmapWorkerTask(image);
    		final AsyncDrawable asyncDrawable = new AsyncDrawable(mResource, mLoadingImage, mAsyncTask);
    		image.setImageDrawable(asyncDrawable);
    		mAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, mActualImageId);
    	}


    首先,创建AsyncTask对象mAsyncTask;

    然后,创建一个异步drawable对象asyncDrawable,调用ImageView对象image的setImageDrawable方法。到这步,我们界面上显示的暂时是一个临时的图片,如:


    最后,我们启动AsyncTask去解码,并最终解码获得图片的drawable对象。使用ImageView的接口函数setImageDrawable接口将最终图片显示内容显示出来。实例如下图:



  • 相关阅读:
    anime.js 学习笔记
    swiper 报错 ‘ Can't find variable: Dom7’
    团队管理(二)
    团队管理(一)
    针对数值型数据的相关记录
    react+echarts折柱图实现
    侧边广告之心跳动画
    浅谈尾调用和尾递归
    elementUI 日期选择器获取CRON值
    elementUI 日期选择器之禁止年份事件二
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3323159.html
Copyright © 2011-2022 走看看