开发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 的一些知识,可以查看官方文档学习。

  1. /**
  2. *
  3. * @param urlStr 所需要加载的图片的url,以String形式传进来,可以把这个url作为缓存图片的key
  4. * @param image ImageView 控件
  5. */
  6. private void loadBitmap(String urlStr, ImageView image) {
  7. AsyncImageLoader asyncLoader = new AsyncImageLoader(image, mLruCache);//什么一个异步图片加载对象
  8. Bitmap bitmap = asyncLoader.getBitmapFromMemoryCache(urlStr);//首先从内存缓存中获取图片
  9. if (bitmap != null) {
  10. image.setImageBitmap(bitmap);//如果缓存中存在这张图片则直接设置给ImageView
  11. } else {
  12. image.setImageResource(R.drawable.thum);//否则先设置成默认的图片
  13. asyncLoader.execute(urlStr);//然后执行异步任务AsycnTask 去网上加载图片
  14. }
  15. }

然后在自定义Adapter的getView()方法方法中调用上面的loadBitmap()方法。

这样就实习了图片异步加载和内存缓存了。

看一下效果图:

当然没有磁盘缓存的ListView 绝对是不行的。ListView还有很多需要优化的技巧需要我们去不断学习。比如说图片懒加载。

Android ListView 图片异步加载和图片内存缓存的更多相关文章

  1. [android] 数据的异步加载和图片保存

    把从网络获取的图片数据保存在SD卡上, 先把权限都加上 网络权限 android.permission.INTERNET SD卡读写权限 android.permission.MOUNT_UNMOUN ...

  2. ListView在异步加载动态图片时,往往最后一项或几项被遮盖(IM场景居多)

    如果ListView中得默认图片比较小,新图片加载后,撑大ListView中的对应项,导致最后一项或几项被覆盖. 解决思路: 1.默认图片设定和新图大小一样,换句话说,新图加载后转成和默认图片一样的大 ...

  3. (转)Android技术积累:图片异步加载

    当在ListView或GridView中要加载很多图片时,很容易出现滑动时的卡顿现象,以及出现OOM导致FC(Force Close). 会出现卡顿现象主要是因为加载数据慢,要等数据加载完才能显示出来 ...

  4. Android新浪微博客户端(七)——ListView中的图片异步加载、缓存

    原文出自:方杰|http://fangjie.info/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54 该项目代码已经放到git ...

  5. Android图片异步加载框架Android-Universal-Image-Loader

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个 ...

  6. Android 图片异步加载的体会,SoftReference已经不再适用

      在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的 ...

  7. Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  8. Android图片异步加载之Android-Universal-Image-Loader(转)

    今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...

  9. [置顶] Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

随机推荐

  1. 捉襟见肘之TableView的手势(删除、编辑等)与转场动画手势冲突

    在使用PresentModel的方式进行转场动画时,出现UIPercentDrivenInteractiveTransition和 UITableView的自带手势冲突,问题需要总结,今天系统复习和总 ...

  2. POJ3208:Apocalypse Someday

    传送门 很神奇的一道题,正解是AC自动机+数位DP,个人感觉POPOQQQ大爷的方法更方便理解. 按照一般套路,先搞个DP预处理,设$f[i][0/1/2/3]$分别表示对于$i$位数,其中有多少个前 ...

  3. python 安装包总结

    PIL安装(Centos6.6) 1. 安装PIL所需的系统库 (centos6.6)yum install zlib zlib-devel -yyum install libjpeg libjpeg ...

  4. java编程思想-接口总结

    "确定接口是理想选择,因而应该总是选择接口而不是具体的类."这其实是一种诱饵.当然,对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂. 许多人都掉进了这种诱惑的陷阱, ...

  5. properties 配置文件中值换行的问题

    在使用properties配置文件的时候我们经常碰到如下两个问题 1:当a=b中的b值内容特别长的时候为了阅读方便我们手动换行,但如果我们直接回车那么后面的数据就会丢失.那如何解决呢? 例如: a=a ...

  6. 安装Flask

    安装Flask步骤 输入网址https://bitbucket.org/pypa/setuptools](https://bitbucket.org/pypa/setuptools,回车后进入setu ...

  7. HashMap与ArrayList互相嵌套的代码实现

    HashMap嵌套ArrayList的代码实现 结果要求为 三国演义            吕布            周瑜笑傲江湖           令狐冲            林平之神雕侠侣  ...

  8. e_msg_c_gs_enter_gs_req

    e_msg_c_gs_enter_gs_req 就是到GS上验证客户端发送的token是否存在,如果存在返回成功,并把该token删除

  9. EasyUI学习笔记之panel

    <easyUI panel 属性:> <!--引入easyUI panel 组件 设置宽,高,定义标题(默认在左上角),设置图标iconCls:'icon-ok',引入工具tools ...

  10. YOURPHP的分页完整版

    html代码 <?php print_r($ser['searchtype']);?> <select name="searchtype"> <opt ...