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接口将最终图片显示内容显示出来。实例如下图:
Android图片异步加载的方法的更多相关文章
- Android 图片异步加载的体会,SoftReference已经不再适用
在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>> 这样软引用的 ...
- Android图片异步加载之Android-Universal-Image-Loader
将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...
- Android图片异步加载之Android-Universal-Image-Loader(转)
今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...
- [置顶] Android图片异步加载之Android-Universal-Image-Loader
将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...
- Android图片异步加载
原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/A ...
- Android图片异步加载框架Android-Universal-Image-Loader
版权声明:本文为博主原创文章,未经博主允许不得转载. Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个 ...
- Android 图片异步加载 加载网络图片
最近用到了加载网络图片,研究了一下,写一点简单的介绍: 首先创建一个线程去取图片(网络请求必须放在线程中): /** * 使用继承java.lang.Thread类的方式创建一个线程 * 直接取图片, ...
- Android ListView 图片异步加载和图片内存缓存
开发Android应用经常需要处理图片的加载问题.因为图片一般都是存放在服务器端,需要联网去加载,而这又是一个比较耗时的过程,所以Android中都是通过开启一个异步线程去加载.为了增加用户体验,给用 ...
- android ListView异步加载图片(双缓存)
首先声明,参考博客地址:http://www.iteye.com/topic/685986 对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求... ...
随机推荐
- eclipse:Tomcat设置jvm,解决java.lang.OutOfMemoryError: Java heap space 堆内存溢出
eclipse 有启动参数里设置jvm大小,因为eclipse运行时自己也需要jvm,所以eclipse.ini里设置的jvm大小不是具体某个程序运行时所用jvm的大小,这和具体程序运行的jvm大小无 ...
- 命令自动补全模块rlcomplete
rlcomplete定义了针对readline模块的命令自动补全函数. 当在unix平台下导入这个模块之后(前提是readline模块可用),一个Complete的实例会自动生成,并且 ...
- IOS 表视图(UITableVIew)的使用方法(3)名单的索引显示
当数据量特别大时,简单地以role进行分段,对实际查找的效率提升并不大.就像上一节开头所说,开发者可以根据球员名字的首字母进行分段,且分成26段.由于段数较多,可以使用UITableView的索引机制 ...
- 帝国cms7.0忘记后台管理账户用户名密码
最近刚登陆以前的网站,但是发现自己的后台管理用户名密码已经忘记,于是到帝国cms论坛里面找了一下解决方案,成功解决问题.特此分享一下解决成功经验. 原帖地址:http://bbs.phome.net/ ...
- sqlite详细介绍
------------------------------------------------------------------------------SQLite简介-------------- ...
- 读书笔记: nodejs API 参考
>> bufferBuffer对象是全局对象Buffer支持的编码方式:ascii, utf8, base64, binarynew Buffer(size)new Buffer(arra ...
- 射频识别技术漫谈(7)——ID卡
ID(Identification)是识别的意思,ID卡就是识别卡.ID卡包含范围广泛,只要具有识别功能的卡片都可以叫ID卡,例如条码卡,磁卡都可以是ID卡,我们这儿说的当然是射频识别卡. 射频ID卡 ...
- QT4/QT5设置界面风格(QT4支持更多的Windows界面风格)
#include "mainwindow.h" #include <QApplication> #include <QTextCodec> #include ...
- 由世纪互联运营的 Windows Azure 现已在中国正式发布
我们非常高兴地公开发布由世纪互联运营的 Windows Azure,这标志着我们成为第一家在中国国内正式提供公共云平台技术的跨国公司.这一伟大成就的实现,得益于 Microsoft 与世纪互联的 ...
- 先登录 在跳转到tabBar
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...