Android ListView 图片异步加载和图片内存缓存
开发Android应用经常需要处理图片的加载问题。因为图片一般都是存放在服务器端,需要联网去加载,而这又是一个比较耗时的过程,所以Android中都是通过开启一个异步线程去加载。为了增加用户体验,给用户省流量,一般把加载完的图片先缓存下来,下次加载的时候就不需要再联网去服务器端加载。图片缓存一般分为一级缓存(即内存缓存)和二级缓存(即磁盘缓存)。这里只讲一级缓存。
内存缓存就是把加载完的图片先放在手机内存中,等下次加载的时候再从内存中取出来。
优点是速度快,缺点是不能长久保存,用户退出应用程序之后内存缓存就被回收了。而且加载太多会抛出java.lang.OutOfMemory异常。
磁盘缓存就是把加载完的图片放到手机内置存储卡或SD卡中。下次加载的时候在从里面取出来。
优点是能够长期保存,缺点是速度较慢,为了不影响用户体验,也一般是通过异步线程去取磁盘中的缓存图片;还有一个就是用户卸载应用程序后这些缓存文件不会随着删除,浪费了用户的磁盘空间,需要用户手动删除。
图片缓存很多人都是用软引用SoftRReference来处理,但是Android官方并不推荐这么用。
Android官方给出的理由是:Note: In the past, a popular memory cache implementation was a SoftReference
or WeakReference
bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash.
所以我们一般使用LruCache这个类,这个类可以这样理解:它就是一个内存缓存对象,你的图片就缓存在这个类里面。(Java中什么都是对象)这个类是在API 12中才有的,不过幸运的是Android官方把它加入了v4包中,所以1.6以后的都可以使用这个类。这个类用起来也比较简单(官方文档上也讲的很详细)。
下面讲一下我是怎样用的:
首先是给ListView 自定义一个Adapter(继承自BaseAdapter),然后在这个类中申明一个成员变量LruCache ,而不能在getView()方法中申明。因为一个ListView所有的Item项只能维护这一个LruCache 。LruCache有一个构造方法LruCache(int maxSize) ,参数就是这个缓存空间最大的容量(多少字节)。申明一个LruCache对象一般需要复写它的sizeOf(K key, V value),用这个方法改变每个缓存条目计算大小的方式。Android源码中默认是返回1,说默认是以个数来计算的。(其实这里我也不太理解,有懂的朋友还望不吝赐教。)
Android sizeof()的源码:
不过我是参照官方文档写的。
private final int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取当前应用程序所分配的最大内存 ;//只分5分之一用来做图片缓存 private LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>( cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) {//复写sizeof()方法 // replaced by getByteCount() in API 12 ; //这里是按多少KB来算 } };
然后写一个异步加载图片的类AsyncImageLoader ; 这个类采用AsyncTask来异步加载图片。
package com.folyd.tuan.util; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.graphics.Bitmap; import android.graphics.BitmapFactory; /** * 简单的图片加载工具类,此类没有涉及到图片缓存。 * @author Folyd * */ public class SimpleImageLoader { public static Bitmap getBitmap(String urlStr) throws IOException{ Bitmap bitmap; URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(*); conn.setDoInput(true); conn.connect(); InputStream is = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(is); is.close(); return bitmap; } }
SimpleImageLoader 的getBitmap方法是一个简单的从网上获取图片的方法。
/** * * @param urlStr 所需要加载的图片的url,以String形式传进来,可以把这个url作为缓存图片的key * @param image ImageView 控件 */ private void loadBitmap(String urlStr, ImageView image) { AsyncImageLoader asyncLoader = new AsyncImageLoader(image, mLruCache);//什么一个异步图片加载对象 Bitmap bitmap = asyncLoader.getBitmapFromMemoryCache(urlStr);//首先从内存缓存中获取图片 if (bitmap != null) { image.setImageBitmap(bitmap);//如果缓存中存在这张图片则直接设置给ImageView } else { image.setImageResource(R.drawable.thum);//否则先设置成默认的图片 asyncLoader.execute(urlStr);//然后执行异步任务AsycnTask 去网上加载图片 } }
然后在自定义的Adapter中封装一个加载图片的方法。这里涉及到AsyncTask 的一些知识,可以查看官方文档学习。
- /**
- *
- * @param urlStr 所需要加载的图片的url,以String形式传进来,可以把这个url作为缓存图片的key
- * @param image ImageView 控件
- */
- private void loadBitmap(String urlStr, ImageView image) {
- AsyncImageLoader asyncLoader = new AsyncImageLoader(image, mLruCache);//什么一个异步图片加载对象
- Bitmap bitmap = asyncLoader.getBitmapFromMemoryCache(urlStr);//首先从内存缓存中获取图片
- if (bitmap != null) {
- image.setImageBitmap(bitmap);//如果缓存中存在这张图片则直接设置给ImageView
- } else {
- image.setImageResource(R.drawable.thum);//否则先设置成默认的图片
- asyncLoader.execute(urlStr);//然后执行异步任务AsycnTask 去网上加载图片
- }
- }
然后在自定义Adapter的getView()方法方法中调用上面的loadBitmap()方法。
这样就实习了图片异步加载和内存缓存了。
看一下效果图:
当然没有磁盘缓存的ListView 绝对是不行的。ListView还有很多需要优化的技巧需要我们去不断学习。比如说图片懒加载。
Android ListView 图片异步加载和图片内存缓存的更多相关文章
- [android] 数据的异步加载和图片保存
把从网络获取的图片数据保存在SD卡上, 先把权限都加上 网络权限 android.permission.INTERNET SD卡读写权限 android.permission.MOUNT_UNMOUN ...
- ListView在异步加载动态图片时,往往最后一项或几项被遮盖(IM场景居多)
如果ListView中得默认图片比较小,新图片加载后,撑大ListView中的对应项,导致最后一项或几项被覆盖. 解决思路: 1.默认图片设定和新图大小一样,换句话说,新图加载后转成和默认图片一样的大 ...
- (转)Android技术积累:图片异步加载
当在ListView或GridView中要加载很多图片时,很容易出现滑动时的卡顿现象,以及出现OOM导致FC(Force Close). 会出现卡顿现象主要是因为加载数据慢,要等数据加载完才能显示出来 ...
- Android新浪微博客户端(七)——ListView中的图片异步加载、缓存
原文出自:方杰|http://fangjie.info/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54 该项目代码已经放到git ...
- Android图片异步加载框架Android-Universal-Image-Loader
版权声明:本文为博主原创文章,未经博主允许不得转载. Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个 ...
- 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上关于图片异步加载的开源项目,就 ...
随机推荐
- 捉襟见肘之TableView的手势(删除、编辑等)与转场动画手势冲突
在使用PresentModel的方式进行转场动画时,出现UIPercentDrivenInteractiveTransition和 UITableView的自带手势冲突,问题需要总结,今天系统复习和总 ...
- POJ3208:Apocalypse Someday
传送门 很神奇的一道题,正解是AC自动机+数位DP,个人感觉POPOQQQ大爷的方法更方便理解. 按照一般套路,先搞个DP预处理,设$f[i][0/1/2/3]$分别表示对于$i$位数,其中有多少个前 ...
- python 安装包总结
PIL安装(Centos6.6) 1. 安装PIL所需的系统库 (centos6.6)yum install zlib zlib-devel -yyum install libjpeg libjpeg ...
- java编程思想-接口总结
"确定接口是理想选择,因而应该总是选择接口而不是具体的类."这其实是一种诱饵.当然,对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂. 许多人都掉进了这种诱惑的陷阱, ...
- properties 配置文件中值换行的问题
在使用properties配置文件的时候我们经常碰到如下两个问题 1:当a=b中的b值内容特别长的时候为了阅读方便我们手动换行,但如果我们直接回车那么后面的数据就会丢失.那如何解决呢? 例如: a=a ...
- 安装Flask
安装Flask步骤 输入网址https://bitbucket.org/pypa/setuptools](https://bitbucket.org/pypa/setuptools,回车后进入setu ...
- HashMap与ArrayList互相嵌套的代码实现
HashMap嵌套ArrayList的代码实现 结果要求为 三国演义 吕布 周瑜笑傲江湖 令狐冲 林平之神雕侠侣 ...
- e_msg_c_gs_enter_gs_req
e_msg_c_gs_enter_gs_req 就是到GS上验证客户端发送的token是否存在,如果存在返回成功,并把该token删除
- EasyUI学习笔记之panel
<easyUI panel 属性:> <!--引入easyUI panel 组件 设置宽,高,定义标题(默认在左上角),设置图标iconCls:'icon-ok',引入工具tools ...
- YOURPHP的分页完整版
html代码 <?php print_r($ser['searchtype']);?> <select name="searchtype"> <opt ...