Android 高效加载图片

来源:互联网 发布:淘宝助理五笔怎么打? 编辑:程序博客网 时间:2024/04/29 19:00

1.加载合适大小的图片

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,        int reqWidth, int reqHeight) {    final BitmapFactory.Options options = new BitmapFactory.Options();       // inJustDecodeBounds set true,只获取图片信息    options.inJustDecodeBounds = true;    BitmapFactory.decodeResource(res, resId, options);    // 获取缩小倍数    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);    // inJustDecodeBounds set false    options.inJustDecodeBounds = false;    return BitmapFactory.decodeResource(res, resId, options);}//测量缩小倍数public static int calculateInSampleSize(            BitmapFactory.Options options, int reqWidth, int reqHeight) {    // 获取图片宽高    final int height = options.outHeight;    final int width = options.outWidth;    int inSampleSize = 1;    if (height > reqHeight || width > reqWidth) {        final int halfHeight = height / 2;        final int halfWidth = width / 2;        //将inSampleSize设置成2的指数倍        while ((halfHeight / inSampleSize) > reqHeight                && (halfWidth / inSampleSize) > reqWidth) {            inSampleSize *= 2;        }    }    return inSampleSize;}

2.异步加载图片

简单的异步加载图片

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {    private final WeakReference<ImageView> imageViewReference;    private int data = 0;    public BitmapWorkerTask(ImageView imageView) {        // 使用WeakReference存储imageView,因为imageView可能会被GC回收,如果被GC回收,那么就说明就不用加载图片        imageViewReference = new WeakReference<ImageView>(imageView);    }    // 异步加载图片    @Override    protected Bitmap doInBackground(Integer... params) {        data = params[0];        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));    }    // 加载完成,确定imageView是否还存在    @Override    protected void onPostExecute(Bitmap bitmap) {        if (imageViewReference != null && bitmap != null) {            final ImageView imageView = imageViewReference.get();            if (imageView != null) {                imageView.setImageBitmap(bitmap);            }        }    }}

使用

public void loadBitmap(int resId, ImageView imageView) {    BitmapWorkerTask task = new BitmapWorkerTask(imageView);    task.execute(resId);}

如果在ListView,和GridView中使用,往往会因为用户的滑动,会产生大量的异步线程,还可能导致图片的重复加载,或者是加载了图片却并不需要显示(该条目已经不需要显示)。那么就要进行同步处理。
首先,避免不必要的task运行,可以采用之前用WeakReference存储ImageView的方法,将task和目标图片关联起来。在这里,可以采用创建BitmapDrawable 的子类来进行管理。

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

在执行task之前,将图片和ImageView绑定起来

public void loadBitmap(int resId, ImageView imageView) {    if (cancelPotentialWork(resId, imageView)) {        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);        final AsyncDrawable asyncDrawable =                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);        imageView.setImageDrawable(asyncDrawable);        task.execute(resId);    }}

判断task是否必要执行

public static boolean cancelPotentialWork(int data, ImageView imageView) {    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);    if (bitmapWorkerTask != null) {        final int bitmapData = bitmapWorkerTask.data;        // If bitmapData is not yet set or it differs from the new data        if (bitmapData == 0 || bitmapData != data) {            // Cancel previous task            bitmapWorkerTask.cancel(true);        } else {            // The same work is already in progress            return false;        }    }    // No task associated with the ImageView, or an existing task was cancelled    return true;}//判断task是否已经创建private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {   if (imageView != null) {       final Drawable drawable = imageView.getDrawable();       if (drawable instanceof AsyncDrawable) {           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;           return asyncDrawable.getBitmapWorkerTask();       }    }    return null;}

最后,修改之前的代码,判断ImageView和task,确定图片是否应该显示

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {    ...    @Override    protected void onPostExecute(Bitmap bitmap) {        if (isCancelled()) {            bitmap = null;        }        if (imageViewReference != null && bitmap != null) {            final ImageView imageView = imageViewReference.get();            final BitmapWorkerTask bitmapWorkerTask =                    getBitmapWorkerTask(imageView);            if (this == bitmapWorkerTask && imageView != null) {                imageView.setImageBitmap(bitmap);            }        }    }}
1 0