拆轮子:LocalImageLoader

我们在开发中遇到了一个问题:制作本地图片选择功能时,加载图片可以选择fresco,自带缓存,加载迅速。但是在加载screenshot这个截图相册的时候,fresco加载异常缓慢。所以我们需要一个自己写一个相册加载类。另外如果不想用第三方开源库,这个类也是一个很好地选择。

我们一步一步来。
第一步:
简单粗暴的多线程加载

public void loadImage(final String path, final ImageView imageView) {
        imageView.setTag(path);

        // UI线程
        if (mHandler == null) {
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
                    ImageView imageView = holder.imageView;
                    Bitmap bm = holder.bitmap;
                    String path = holder.path;
                    if (imageView.getTag().toString().equals(path)) {
                        imageView.setImageBitmap(bm);
                    }
                    holder.imageView = null;//否则随着手势滑动,内存不会释放,滑动一会儿直接就oom了
                }
            };
        }


        Runnable runnable = new Runnable() {
            @Override
            public void run() {

                ImageSize imageSize = getImageViewWidth(imageView);

                int reqWidth = imageSize.width;
                int reqHeight = imageSize.height;

                Bitmap bm = decodeSampledBitmapFromResource(path, reqWidth,
                        reqHeight);
//                addBitmapToLruCache(path, bm);//将读取出的bitmap加入缓存
                ImgBeanHolder holder = new ImgBeanHolder();
//                holder.bitmap = getBitmapFromLruCache(path);
                holder.bitmap = bm;
                holder.imageView = imageView;
                holder.path = path;
                Message message = Message.obtain();
                message.obj = holder;
                // Log.e("TAG", "mHandler.sendMessage(message);");
                mHandler.sendMessage(message);
//                mPoolSemaphore.release();
            }
        };

        new Thread(runnable).start();
    }



这个时候,相册可以加载出来,但是滑动会非常卡顿。
运行程序,我们可以在monitor中看到,随着手势滑动,卡顿非常严重,CPU占用也很高。在ddms中看到瞬间多了30多个线程。。。。
并且没有缓存,滑出屏幕的所有元素,再滑动回来,都是空白,需要重新加载。



第二部:
加上lru缓存
下面为loadImage方法中主要的改动
        Bitmap bm = getBitmapFromLruCache(path);
        Log.d("cchen", path + " hit " + bm);

  //从缓存取bitmap,判断是否命中
        if (bm != null) {
            ImgBeanHolder holder = new ImgBeanHolder();
            holder.bitmap = bm;
            holder.imageView = imageView;
            holder.path = path;
            Message message = Message.obtain();
            message.obj = holder;
            mHandler.sendMessage(message);

            return;
        }

//............
    Bitmap bm = decodeSampledBitmapFromResource(path, reqWidth,
                        reqHeight);
                [color=red]addBitmapToLruCache(path, bm)[/color];//将读取出的bitmap加入缓存
                ImgBeanHolder holder = new ImgBeanHolder();
                holder.bitmap = getBitmapFromLruCache(path);
//                holder.bitmap = bm;
                holder.imageView = imageView;


//............


加上LRU后,第一次加载的速度差不多。但是来回滑动后,缓存会命中很多,这样滑动一屏,新建的线程只有原来的一半15个,而且滑动回来后,很多图片也还在显示,不需要重新加载。卡顿减轻了很多但仍然有。
并且加载速度不够理想。

第三步:

土逼啃蹄牛




猜你喜欢

转载自ccsosnfs.iteye.com/blog/2393058