开发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. CSS3-border-radius的兼容写法大全

    <!DOCTYPE html><html lang="zh-cn"><head> <meta charset="utf-8&qu ...

  2. map遍历方法

    java中遍历MAP的几种方法 Java代码 Map<String,String> map=new HashMap<String,String>();    map.put(& ...

  3. IEquatable 的Equals 代替 object 的Equals

    struct Point2 : IEquatable<Point2> { public int X { get; set; } public int Y { get; set; } pub ...

  4. ORACLE函数大全

    SQL中的单记录函数 1.ASCII 返回与指定的字符对应的十进制数; SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ...

  5. 自然语言16.1_Python自然语言处理学习笔记之信息提取步骤&分块(chunking)

    QQ:231469242 欢迎喜欢nltk朋友交流 http://www.cnblogs.com/undercurrent/p/4754944.html 一.信息提取模型 信息提取的步骤共分为五步,原 ...

  6. C#操作XML,如何获取指定节点值?

    博客园提问,结合网友回答http://q.cnblogs.com/q/36082/   打开是treelist树形显示xml所有节点,递归来实现 xmlDoc = new XmlDocument(); ...

  7. socket+mysql

    测试windows 下 Socket+Mysql调用. 环境: OS:Win7; DBMS:Mysql;  IDE:codeblockS. server: #include <WINSOCK2. ...

  8. Unity Shader Lab

    http://docs.unity3d.com/460/Documentation/Manual/SL-BuiltinValues.html http://docs.unity3d.com/Manua ...

  9. vnc服务器配置实例

    系统环境为CentOS.RHEL. 临时需要远程连接,参考:http://www.centoscn.com/CentOS/Intermediate/2013/0917/1641.html 一.安装.启 ...

  10. 一些分享微博,qq啥的js

    <div class="bdsharebuttonbox" style="float:right"><a href="#" ...