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()的源码:

/**
     * Returns the size of the entry for {@code key} and {@code value} in
     * user-defined units.  The default implementation returns 1 so that size
     * is the number of entries and max size is the maximum number of entries.
     *
     * <p>An entry‘s size must not change while it is in the cache.
     */
    protected int sizeOf(K key, V value) {
        return 1;
    }

不过我是参照官方文档写的。

private final int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取当前应用程序所分配的最大内存
    private final int cacheSize = maxMemory / 5;//只分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
            return bitmap.getRowBytes() * bitmap.getHeight() / 1024; //这里是按多少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(5*1000);
        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 的一些知识,可以查看官方文档学习。

[java] view plaincopyprint?

  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还有很多需要优化的技巧需要我们去不断学习。比如说图片懒加载。

时间: 2024-10-06 06:12:42

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

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

把从网络获取的图片数据保存在SD卡上, 先把权限都加上 网络权限 android.permission.INTERNET SD卡读写权限 android.permission.MOUNT_UNMOUNT_FILESYSTEMS android.permission.WRITE_EXTERNAL_STORAGE 总体布局  写界面,使用ListView,创建条目的布局文件,水平摆放的ImageView TextView 在activity中获取到ListView对象,调用setAdapter()方

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

当在ListView或GridView中要加载很多图片时,很容易出现滑动时的卡顿现象,以及出现OOM导致FC(Force Close). 会出现卡顿现象主要是因为加载数据慢,要等数据加载完才能显示出来.可以通过将数据分页显示,以及将耗时的图片加载用异步的方式和图片缓存,这样就可以解决卡顿的问题. 大部分开发者在ListView或GridView加载图片时,都会在getView方法里创建新的线程去异步加载图片.然而,当屏幕快速向下滑动时,每个划过的Item都会调用getView一次,即会创建出很多

浅谈Android中的异步加载之ListView中图片的缓存及优化三

     隔了很久没写博客,现在必须快速脉动回来.今天我还是接着上一个多线程中的异步加载系列中的最后一个使用异步加载实现ListView中的图片缓存及其优化.具体来说这次是一个综合Demo.但是个人觉得里面还算有点价值的就是里面的图片的缓存的实现.因为老实说它确实能在实际的项目中得到很好的应用.主要学习来源于慕课网中的异步加载学习,来自徐宜生大神的灵感.本次也就是对大神所讲知识的一个总结及一些个人的感受吧. 这次是一个综合的Demo,主要里面涉及到的知识主要有:网络编程.异步加载.JSON解析.

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

原文出自:方杰|http://fangjie.sinaapp.com/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo 一.ListView的图片异步加载 我们都知道对每一个Weibo Item都有用户头像,而且每一条微博还可能带有图片.如果在加载列表的同时加载图片,这样有几个缺点,第一很费事,界面卡住,用户体验很不

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

将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就顺便整理记录下来,作为这一个多月来博客的重新开火做饭吧.从今天起我会陆续恢复博客的更新,也希望大家继续支持. 今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异

简单的ListView中item图片异步加载

前言: 在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现在就讲讲当图片被完全获取到后在显示的方法. 一,效果图:       初始化:                                                   获取后:                         1.1,效果思路: 初始化的时候默认ImageView显示一张白色的图

Android编程之图片(异步)加载类

应某人之请,写一篇关于图片加载类.其实,网上有很多这样的类,而且比较推崇的是来自google中开源中的一篇.他写的比较好了,而且注意了内存优化,下面贴出它的图片下载类: [java] view plaincopy /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not 

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

今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决方案.做Android的同学都知道,Android加载大量图片时,由于系统分配给图片加载的内存大小有限,所以,如果加载图片量非常大的话容易报OOM异常,关于这个异常已经有不少解决方案了,我就不赘述.下面就简要介绍下这个开源项目的主要功能和使用: 一.功能概要 多线程图片加载: 灵活更改ImageLo

Android图片异步加载

原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/Android-Universal-Image-Loader 开发Android程序,一般情况下都会有两个操作,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操作),为了减少网络操作,加快图片加载速度就需要对图片进行缓存,所以网上的好多图片异步加载方法都是与图片的