Android图片异步加载

分享到:

  开发Android程序,一般情况下都会有两个操作,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操作),为了减少网络操作,加快图片加载速度就需要对图片进行缓存,所以网上的好多图片异步加载方法都是与图片的缓存紧密关联的。但也有可能用户已经有了缓存的相关类库,这样使用起来就会有点麻烦。

  最近一段处理跟图片相关的问题,本来是自己写的图片加载,不过有些状态的控制还是比较烦人的,比如ListView滚动时ImageView的重用,所以本着偷懒与充分利用现有资源的态度去网上搜罗图片异步加载的代码,最终在GreenDroid UI库中找到一个,其中有个AsyncImageView的自定义View用于异步加载图片,不过也像网上的大多数图片异步加载方法一样,是跟图片的缓存关联在一起的,不过只是很简单的内存缓存,无文件缓存。图片的加载方法也如其他的一样是写死了的,这就限制了其使用范围,只可通过InputStream 来decode图片,而像生成缩略图或其他一些图片处理的异步处理就无法用途。修改现有类库总比自己从头写来的简单,于是稍微修改了下 AsyncImageView,使其可以自定义缓存与图片加载方法,对于AsyncImageView只有一点点的修改,大都是别人源码。

1. 核心类

  ImageLoader:图片加载核心类,内部使用线程池加载图片

  ImageRequest:表示一个图片加载的请求

  AsyncImageView:自定义的图片异步加载View

  LoadMethod:自定义图片加载方法的接口,可以通过实现此接口来自定义图片的加载方法

  CacheCallback:缓存接口,可以通过实现此接口实现对缓存的读写

AsyncImageView.OnImageViewLoadListener:图片加载状态监听(开始,失败,结束)

2。图片加载方法

 public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final Handler h = mHandler;
Bitmap bitmap = null;
Throwable throwable = null;
h.sendMessage(Message.obtain(h, ON_START));
try {
if (TextUtils.isEmpty(mUrl)) {
throw new Exception("The given URL cannot be null or empty");
}
// 如果自定义了加载方法,则用自定义的方法
if (mLoadMethod != null) {
bitmap = mLoadMethod.load(mUrl);
} else {
InputStream inputStream = null;
// Asset
if (mUrl.startsWith("file:///android_asset/")) {
inputStream = sAssetManager.open(mUrl.replaceFirst(
"file:///android_asset/", ""));
}
// File
else if (mUrl.startsWith("file:///") || mUrl.startsWith("/")) {
if (mUrl.startsWith("file:///"))
mUrl = mUrl.replaceFirst("file:///", "/");
inputStream = new FileInputStream(mUrl);
}
// NetWork
else {
// 在用URL类加载图片时,发现有的机型上面通过URL类获得的InputStream解析获得的图片总是null,故使用HttpClient
HttpGet httpRequest = new HttpGet(mUrl);
HttpClient httpclient = new DefaultHttpClient();
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 5000);
httpRequest.setParams(httpParams);
HttpResponse response = (HttpResponse)httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();
BufferedInputStream bi = new BufferedInputStream(instream);
inputStream = bi;
}
// 虽然AsyncImageView中有设置BitmapFactory.Options的方法,但一般情况下都未知图片的大小,也就无法计算相应的inSampleSize,
// 也就无法设置相应的BitmapFactory.Options,所以一般情况下还是根据自己的需要自定义LoadMethod为好
bitmap = BitmapFactory.decodeStream(inputStream, null,
(mOptions == null) ? sDefaultOptions : mOptions);
inputStream.close();
}
if (mBitmapProcessor != null && bitmap != null) {
final Bitmap processedBitmap = mBitmapProcessor.processImage(bitmap);
if (processedBitmap != null) {
bitmap.recycle();
bitmap = processedBitmap;
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "Error while fetching image", e);
throwable = e;
}
if (bitmap == null) {
if (throwable == null) {
throwable = new Exception("Skia image decoding failed");
}
h.sendMessage(Message.obtain(h, ON_FAIL, throwable));
} else {
h.sendMessage(Message.obtain(h, ON_END, bitmap));
if (mCache != null) {
mCache.writeCache(TextUtils.isEmpty(mCacheKey) ? mUrl : mCacheKey, bitmap);
}
}
}

  如果自定义了LoadMethod,会调用相应的方法加载图片,如果没有自定义,会使用默认的加载方法,可以加载本地图片,Asset图片与网络图片,GreenDroid的源码中加载网络图片是用的URL的,但我们以前在加载网络图片时遇到一个问题,有的机型通过URL类获得的 ImputStream解析图片总是返回null,所以就改为了HttpClient。

3。使用方法

通过AsyncImageView的setPath方法来加载图片,setPath有3个重载方法:

public void setPath(String path)

public void setPath(String path, LoadMethod loadMethod)

public void setPath(String path, LoadMethod loadMethod, String cacheKey)

第一个参数指定要加载的图片的路径,第二个参数为自定义的图片加载方法,若不指定则用默认的。

至于加第三个参数,是做缓存用的,一般要加载的图片的路径都是唯一的,所以一般用第一个参数来做为缓存的Key就行了,但也有特殊情况,比如读取局域网中的图片,一般都是自动获取IP,所以根据图片路径做为缓存的Key可能是不合适的,所以就需要根据需要手动指定用来作为缓存的Key。

 /**
* 设置要加载的图片的路径, 可为网络路径, Asset文件路径(file:///android_asset), 本地图片路径(file:///或/)
*
* @param path 要加载的图片的路径, 若为null则加载默认图片
* @param loadMethod 自定义的图片加载的方法, 可以null, 使用默认的加载方法
* @param cacheKey 缓存key
*/
public void setPath(String path, LoadMethod loadMethod, String cacheKey) {
// Check the url has changed
if (mBitmap != null && path != null && path.equals(mUrl)) { // TODO mBitmap != null necessary?
return;
}
stopLoading();
mUrl = path;
mCacheKey = cacheKey;
mLoadMethod = loadMethod;
// Setting the url to an empty string force the displayed image to the
// default image
if (TextUtils.isEmpty(mUrl)) {
mBitmap = null;
setDefaultImage();
} else {
if (!mPaused) {
reload();
} else {
// We're paused: let's look in a synchronous and efficient cache
// prior using the default image.
mBitmap = readCache(); // TODO 可能会耗时间
if (mBitmap != null) {
setImageBitmap(mBitmap);
} else {
setDefaultImage();
}
}
}
}
public void reload(boolean force) {
if (mRequest == null && mUrl != null) {
// Prior downloading the image ... let's look in a cache !
mBitmap = null;
if (!force) {
// This may take a long time.
mBitmap = readCache();
}
if (mBitmap != null) {
setImageBitmap(mBitmap);
return;
}
setDefaultImage();
mRequest = new ImageRequest(mUrl, this, mImageProcessor, mOptions, mCacheKey);
mRequest.load(getContext(), mLoadMethod);
if (ImageLoader.getInstance() != null && ImageLoader.getInstance().getCache() == null) {
ImageLoader.getInstance().setCache(mCache);
}
}

  readCache()用于读取缓存,代码如下:

private Bitmap readCache() {
if (mCache != null)
return mCache.readCache(TextUtils.isEmpty(mCacheKey) ? mUrl : mCacheKey);
return null;
}

  其中的mCache由用户能过setCacheCallback(CacheCallback callback)设置用户自定义的缓存方法,由此将图片的加载与缓存分离开,使用户可以使用现有的缓存实现。如要用户指定了缓存Key就使用用户指定的 Key,否则就用图片的路径作Key。

4.AsyncImageView中的其他重要方法

reload([boolean force]):重新加载

stopLoading():停止加载,如果当前正在加载则没有效果,如果加载任务在加载线程池队列中则取消。

setDefaultImage...()类方法:设置默认图片。

setPause(boolean pause):是否加载图片

 

源码下载: asyncimage.zip

昵    称:
验证码:

相关文档:

  • <转>Android开发如何防止内存泄漏
    对于很多处理图形相关的Android开发者来说,大的Bitmap对象可能直接导致软件崩溃,Android平台如何防止内存泄露呢?目前来说Android设备的RA...
  • Android数据采集器PDA还只是尝试
    目前用作便携式数据采集器的工业级PDA,大多数都是基于WindowsCE和WindowMobile的,Android操作系统的工业PDA到目前为止大约就只有韩国蓝鸟...
  • android之listView缓存机制
    activity_main.xml: <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com...
  • Android 中动态加载.jar的实现步骤_Android
    本文介绍动态加载 .jar的实现步骤,这将对你的android开发很有帮助,刚兴趣的朋友可以了解下哦...
  • Android之单选按钮对话框
    main.xml布局文件 <?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation...
  • Android 自定义RadioButton的样式
    我们知道Android控件里的button,listview可以用xml的样式自定义成自己希望的漂亮样式。最近用到RadioButton,利用xml修改android:background="@drawabl...
  • [Android学习系列9]关于Fragment的一些事
    在界面上加入fragment? 方法1.用fragmentManager和fragmentTransaction把fragmentadd上去 方法2.用viewpager绑定一个对应fragment的适配器 Fragment动画过渡...
  • android 学习资料——找资料_侧滑菜单
    /6548903android滑动按钮事件 - androi... [其他代码] android 模仿朋友网推出的菜单效果【改...-1.html Android--滑动按钮 SlipButt...4f.html Android 高仿【...
  • Android 自定义view实现上下滑动,大众点评,美团地图导航界面。_侧滑菜单
    /** * 滑动菜单Demo主Activity * * @a.../** * 双向滑动菜单布局 */ private UpAn...滚动显示和隐藏上侧布局时,手指滑动需要达到的速度。 */ p...; /**...
  • Android 获取网络状态的工具类
    在工作中我们经常要用到网络,网络状态的检查必不可少,这是一个检查当前网络状态的工具类,直接粘过去就能用...
  • Android 中单位讲解
    1. dip(dp): device independent pixels(设备独立像素). dp也就是dip。这个和sp基本类似。如果设置表示长度、高度等属性时可以使用dp 或sp。但如...
  • 品尝 Android(一)AIR 2.5 && Flex Hero
    我关注移动开发很久了,从最初的WidnowsMobile,到塞班,再到iOS、Bada、WindowsPhone7、Meego,直至当前的Android。因为工作和移动领域不沾边,...
  • ImageView显示图像控件(基本用法)
    ImageView主要是用来显示图片的控件,可以对图片进行发大、缩小和旋转的功能。android:scaleType属性指定ImageView控件显示图片的方式,例如:...
  • Android异常:OutOfMemoryError
    在安卓开发中,随着开发的apk越来越复杂,开发在界面上的要求也就变高了,使用的图片也越来越多,内存溢出已经成了不得不注意的问题了...
  • 一个Android Socket的例子
    1.开篇简介 Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类)。要实现Socket的传输,需要构建客户端和服务器端...
  • 浅谈WebView的使用 js alert
    http://blog.csdn.net/liuhe688/article/details/6549263 WebView是Android中一个非常实用的组件,它和Safai、Chrome一样都是基于Webkit网页渲染引擎,可以通...
  • androidmanifest.xml权限中文说明
    程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求,完整列表如下:android.permission.ACCESS_CHECKIN_PROPERTIES允许读写访问...
  • Android--Service之提高
    前言 上一篇博客讲解了一下Android下Service组件的基本使用,对Service组件还不了解的朋友可以先去看看另外一篇Service基础的博客:Android--S...
  • 很牛逼的android真机调试,手机、平板、电视都可
    1、首先通过路由器,搭建局域网 2、手机开wifi,记住ip地址,平板开wifi,记住ip地址,电视开wifi,记住ip 3、然后再eclipse里面“窗口-...
  • Android滚动屏幕截屏工具:scrollscreenshot
    scrollscreenshot是一个支持截取滚动屏幕内容的Android截屏工具。可以截取多张截图,每次截取滚动屏幕内容的一半,状态栏和导航栏只截屏...