通过BitmapFun在项目中使用,结合代码了解一下BitmapFun加载图片的原理,以及最佳使用实践。本文说明不包括BitmapFun的缓存部分。

Android开发在使用ListView和GridView时,可能会有很多网络图片需要加载,通常我们会为每个图片加载启动一个Thread或者直接使用官方提供的AsyncTask,来做Http异步加载,但当每个ImageView子视图都触发一个AsyncTask来异步加载图片时,这样就会产生如下问题:

1. 当用户快速滑动时,ImageView已经被回收,而绑定的线程还在运行,浪费CPU,浪费内存。

2. 无法确保当前视图在结束时,分配的视图已经进入循环队列中给另外一个子视图进行重用,意思就是,图片显示错位了,不该显示到当前问题的图片却显示了,这个是经常遇到的问题。可以结合Adapter中的getView方法的convertView参数理解,ListView是回收和重复利用item的。

3. 无法确保所有的异步任务能够按顺序执行。

在这些问题下,官网给出的答案是,使用下面的方法来保证:

1. ImageView和Task绑定准确的加载对应图片;

2. ImageView和Task无法对应时则取消任务;

BitmapFun实现多线程并发加载图片的原理:

一个类,两个方法:

class AsyncDrawable extends BitmapDrawable{...}

boolean cancelPotentialWork(String url, ImageView imageView){...}

ImageViewResizeTask getBitmapWorkerTask(ImageView imageView){...}

具体代码实现如下:

/**
* 扩展BitmapDrawable类,通过弱引用关联任务BitmapWorkerTask
* BitmapDrawable被用来作为占位图片,绑定任务到ImageView中
*/
private class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> viewResizeTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask viewResizeTask) {
super(res, bitmap);
viewResizeTaskReference = new WeakReference<BitmapWorkerTask>(viewResizeTask);
} public BitmapWorkerTask getBitmapWorkerTask() {
return viewResizeTaskReference.get();
}
} /**
* 确保ImageView执行的是它对应的Task,否则取消任务
* @param url
* @param imageView
* @return
*/
private boolean cancelPotentialWork(String url, ImageView imageView) {
// 获得ImageView对应的Task
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (bitmapWorkerTask != null) {
final String imgUrl = bitmapWorkerTask.url;
if (imgUrl == null || !imgUrl.equals(url)) {
// 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;
} /**
* 获得已经被分配到ImageView的指定的Task
* @param imageView
* @return
*/
private 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;
}

使用方法:

/**
* 异步加载图片
* @param url
* @param imageView
*/
private void loadBitmap(String url, ImageView imageView) {
if (cancelPotentialWork(url, imageView)) {
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
final AsyncDrawable asyncDrawable = new AsyncDrawable(context.getResources(), null, task);
imageView.setImageDrawable(asyncDrawable);
task.execute(url);
}
} /*
* 异步加载图片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. 设置ListView的OnScrollListener事件,在滑动的时候不加载图片

public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
if (!Utils.hasHoneycomb()) {
mImageFetcher.setPauseWork(true);
}
} else {
mImageFetcher.setPauseWork(false);
}
}

2. 在Activity或Fragment的onResume(),onPause(),onDestroy()方法中调用恰当方法非常有用

@Override
public void onResume() {
super.onResume();
mImageFetcher.setExitTasksEarly(false);
} @Override
public void onPause() {
super.onPause();
mImageFetcher.setPauseWork(false);
mImageFetcher.setExitTasksEarly(true);
mImageFetcher.flushCache();
} @Override
public void onDestroy() {
super.onDestroy();
mImageFetcher.closeCache();
}

官网

Processing Bitmaps Off the UI Thread

[原]Android官方图片加载利器BitmapFun解析的更多相关文章

  1. Android之图片加载框架Fresco基本使用(二)

    PS:最近看到很多人都开始写年终总结了,时间过得飞快,又到年底了,又老了一岁. 学习内容: 1.进度条 2.缩放 3.ControllerBuilder,ControllerListener,Post ...

  2. Android之图片加载框架Fresco基本使用(一)

    PS:Fresco这个框架出的有一阵子了,也是现在非常火的一款图片加载框架.听说内部实现的挺牛逼的,虽然自己还没研究原理.不过先学了一下基本的功能,感受了一下这个框架的强大之处.本篇只说一下在xml中 ...

  3. Android自定义图片加载框架

    大神原网址: http://blog.csdn.net/lmj623565791/article/details/41874561  思路: 1. 压缩图片 压缩本地图片: 获得imageview想要 ...

  4. Android 平滑图片加载和缓存库 Glide 使用详解

    在图片加载库烂大街的今天,选择一个适合自己使用的图片加载库已经成为了每一个Android开发者的必经之路.现在市面上知名的图片加载库有UIL,Picasso,Volley ImageLoader,Fr ...

  5. android glide图片加载框架

    项目地址: https://github.com/bumptech/glide Glide作为安卓开发常用的图片加载库,有许多实用而且强大的功能,那么,今天就来总结一番,这次把比较常见的都写出来,但并 ...

  6. Android批量图片加载经典系列——使用xutil框架缓存、异步加载网络图片

    一.问题描述 为提高图片加载的效率,需要对图片的采用缓存和异步加载策略,编码相对比较复杂,实际上有一些优秀的框架提供了解决方案,比如近期在git上比较活跃的xutil框架 Xutil框架提供了四大模块 ...

  7. Android批量图片加载经典系列——afinal框架实现图片的异步缓存加载

    一.问题描述 在之前的系列文章中,我们使用了Volley和Xutil框架实现图片的缓存加载(查看系列文章:http://www.cnblogs.com/jerehedu/p/4607599.html# ...

  8. Android 三大图片加载框架的对比——ImageLoader,Picasso,Glide

    一.ImageLaoder介绍 << Universal ImageLoader 是很早开源的图片缓存,在早期被很多应用使用 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹ass ...

  9. Android批量图片加载经典系列——采用二级缓存、异步加载网络图片

    一.问题描述 Android应用中经常涉及从网络中加载大量图片,为提升加载速度和效率,减少网络流量都会采用二级缓存和异步加载机制,所谓二级缓存就是通过先从内存中获取.再从文件中获取,最后才会访问网络. ...

随机推荐

  1. UIStepper步进器 ——事件驱动型控件,(一个+和-按钮的)

    - (void)viewDidLoad {    [super viewDidLoad];        //步进器 固定的size (94*27), 事件驱动型控件    UIStepper *st ...

  2. Opencv step by step - 加载视频

    刚买了本 "学习Opencv" 这本书,慢慢看起来. 一开始就是加载视频了.当然了,首先你要有个视频 从这里下载了一个: tan@ubuntu:~$ wget http://www ...

  3. 多个div背景图无缝拼接

    公司在做环形进度条的时候遇到了这个问题,上网一搜,原来是因为两个div背景图拼接起来的,所以中间出现了必不可少的缝隙,最后把position改为relative,再加个margin:0,就解决好了,下 ...

  4. Orchard 刨析:导航篇

    之前承诺过针对Orchard Framework写一个系列.本应该在昨天写下这篇导航篇,不过昨天比较累偷懒的去玩了两盘单机游戏哈哈.下面进入正题. 写在前面 面向读者 之前和本文一再以Orchard ...

  5. 趋势or过渡,量子点屏幕真的优于OLED?

    [导读]谁都知道买电视就是要买看起来很爽的产品,但怎么界定这个“爽”字?大部分人所知的是屏幕要够大,再近一步就是分辨率要够高——在这个4K分辨率逐步进入寻常家庭的时代,这两者已经不是选购屏幕类产品的大 ...

  6. node 通用的中间件

    为什么学习Node,因为他的门槛比较高一点,现在比较热门一点. 技术这种东西,用最短的时间学会了收益终身. 1.常用的中间件: // 通用的中间件 //bodyParser connect 内建的中间 ...

  7. [codevs1283]等差子序列(二进制)

    题目:http://codevs.cn/problem/1283/ 分析: 主要就是在每个判定上节省时间.一般的做法是开个数组记录每个数字出没出现,然后每次读入一个数字就以他为中间向两边扩展直到两个对 ...

  8. [bzoj 2005][NOI 2010]能量采集(容斥原理+递推)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2005 分析:首先易得ans=∑gcd(x,y)*2+1 然后我就布吉岛了…… 上网搜了下题解, ...

  9. [bzoj 1026]windy数(数位DP)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总 ...

  10. 重构笔记---MEF框架(上)

    概述 这篇文章的目的是简要分析对比MAF和MEF,并详细举出MEF设计中的细节和扩展上的细节,达到让读者能实际操作的目的.其中,MAF的设计会附上我的代码,其实就是官方的代码我自己手动联系了一遍,但还 ...