拆轮子:LocalImageLoader
我们在开发中遇到了一个问题:制作本地图片选择功能时,加载图片可以选择fresco,自带缓存,加载迅速。但是在加载screenshot这个截图相册的时候,fresco加载异常缓慢。所以我们需要一个自己写一个相册加载类。另外如果不想用第三方开源库,这个类也是一个很好地选择。我们一步一步来。第一步:简单粗暴的多线程加载[code="java"]public void load...
·
我们在开发中遇到了一个问题:制作本地图片选择功能时,加载图片可以选择fresco,自带缓存,加载迅速。但是在加载screenshot这个截图相册的时候,fresco加载异常缓慢。所以我们需要一个自己写一个相册加载类。另外如果不想用第三方开源库,这个类也是一个很好地选择。
我们一步一步来。
第一步:
简单粗暴的多线程加载
这个时候,相册可以加载出来,但是滑动会非常卡顿。
运行程序,我们可以在monitor中看到,随着手势滑动,卡顿非常严重,CPU占用也很高。在ddms中看到瞬间多了30多个线程。。。。
并且没有缓存,滑出屏幕的所有元素,再滑动回来,都是空白,需要重新加载。
第二部:
加上lru缓存
下面为loadImage方法中主要的改动
加上LRU后,第一次加载的速度差不多。但是来回滑动后,缓存会命中很多,这样滑动一屏,新建的线程只有原来的一半15个,而且滑动回来后,很多图片也还在显示,不需要重新加载。卡顿减轻了很多但仍然有。
并且加载速度不够理想。
第三步:
土逼啃蹄牛
我们一步一步来。
第一步:
简单粗暴的多线程加载
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个,而且滑动回来后,很多图片也还在显示,不需要重新加载。卡顿减轻了很多但仍然有。
并且加载速度不够理想。
第三步:
土逼啃蹄牛
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献2条内容
所有评论(0)