Android异步加载 缓存第一章

今天要讲的缓存策略(缓存层分为三层:内存层,磁盘层,网络层)。
当我们第一次打开应用获取图片时,先到网络去下载图片,然后依次存入内存缓存,磁盘缓存,当我们再一次需要用到刚才下载的这张图片时,就不需要再重复的到网络上去下载,直接可以从内存缓存和磁盘缓存中找,由于内存缓存速度较快,我们优先到内存缓存中寻找该图片,如果找到则运用,如果没有找到(内存缓存大小有限),那么我们再到磁盘缓存中去找。只要我们合理的去协调这三层缓存运用,便可以提升应用性能和用户体验。
1、内存层:(手机内存)
内存缓存相对于磁盘缓存而言,速度要来的快很多,但缺点容量较小且会被系统回收,这里的实现我用到了LruCache。LruCache这个类是Android3.1版本中提供的,如果你是在更早的Android版本中开发,则需要导入android-support-v4的jar包。
2、磁盘层:(SD卡)
相比内存缓存而言速度要来得慢很多,但容量很大,这里的实现我用到了DiskLruCache类。DiskLruCache是非Google官方编写,但获得官方认证的硬盘缓存类,该类没有限定在Android内,所以理论上java应用也可以使用DiskLreCache来缓存。这是DiskLruCache类的下载地址:http://pan.baidu.com/s/1o6tPjz8
3、网络层:(移动网络,无线网络)

原理

Android原生为我们提供了一个LruCache,其中维护着一个LinkedHashMap。LruCache可以用来存储各种类型的数据,但最常见的是存储图片(Bitmap)。LruCache创建LruCache时,我们需要设置它的大小,一般是系统最大存储空间的八分之一。LruCache的机制是存储最近、最后使用的图片,如果LruCache中的图片大小超过了其默认大小,则会将最老、最远使用的图片移除出去。
当图片被LruCache移除的时候,我们需要手动将这张图片添加到软引用(SoftReference)中。我们需要在项目中维护一个由SoftReference组成的集合,其中存储被LruCache移除出来的图片。软引用的一个好处是当系统空间紧张的时候,软引用可以随时销毁,因此软引用是不会影响系统运行的,换句话说,如果系统因为某个原因OOM了,那么这个原因肯定不是软引用引起的。

下面叙述一下三级缓存的流程:

当我们的APP中想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,如果LruCache中没有,则去SoftReference中寻找,如果SoftReference中有,则从SoftReference中取出图片使用,同时将图片重新放回到LruCache中,如果SoftReference中也没有图片,则去文件系统中寻找,如果有则取出来使用,同时将图片添加到LruCache中,如果没有,则连接网络从网上下载图片。图片下载完成后,将图片保存到文件系统中,然后放到LruCache中。
LruCache子类ImageCache:

import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.LruCache;

import java.lang.ref.SoftReference;
import java.util.Map;

/**
 * 图片缓存
 */
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
public class ImageCache extends LruCache<String, Bitmap> {
    private Map<String, SoftReference<Bitmap>> cacheMap;

    public ImageCache(Map<String, SoftReference<Bitmap>> cacheMap) {
        super((int) (Runtime.getRuntime().maxMemory() / 8));
        this.cacheMap = cacheMap;
    }

    @Override // 获取图片大小
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override // 当有图片从LruCache中移除时,将其放进软引用集合中
    protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
        if (oldValue != null) {
            SoftReference<Bitmap> softReference = new SoftReference<Bitmap>(oldValue);
            cacheMap.put(key, softReference);
        }
    }

    public Map<String, SoftReference<Bitmap>> getCacheMap() {
        return cacheMap;
    }
}

三级缓存工具类ImageCacheLoader:

  import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.widget.ImageView;

import java.io.File;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

/**
 * 缓存工具类
 */
public class CacheUtil {
    private static CacheUtil instance;

    private Context context;
    private ImageCache imageCache;

    private CacheUtil(Context context) {
        this.context = context;
        Map<String, SoftReference<Bitmap>> cacheMap = new HashMap<>();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { // SDK版本判断
            this.imageCache = new ImageCache(cacheMap);
        }
    }

    public static CacheUtil getInstance(Context context) {
        if (instance == null) {
            synchronized (CacheUtil.class) {
                if (instance == null) {
                    instance = new CacheUtil(context);
                }
            }
        }
        return instance;
    }

    /**
     * 将图片添加到缓存中
     */
    private void putBitmapIntoCache(String fileName, byte[] data) {
        // 将图片的字节数组写入到内存中
        FileUtil.getInstance(context).writeFileToStorage(fileName, data);
        // 将图片存入强引用(LruCache)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            imageCache.put(fileName, BitmapFactory.decodeByteArray(data, 0, data.length));
        }
    }

    /**
     * 从缓存中取出图片
     */
    private Bitmap getBitmapFromCache(String fileName) {
        // 从强引用(LruCache)中取出图片
        Bitmap bm = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) { // SDK版本判断
            bm = imageCache.get(fileName);
            if (bm == null) {
                // 如果图片不存在强引用中,则去软引用(SoftReference)中查找
                Map<String, SoftReference<Bitmap>> cacheMap = imageCache.getCacheMap();
                SoftReference<Bitmap> softReference = cacheMap.get(fileName);
                if (softReference != null) {
                    bm = softReference.get();
                    imageCache.put(fileName, bm);
                } else {
                    // 如果图片不存在软引用中,则去内存中找
                    byte[] data = FileUtil.getInstance(context).readBytesFromStorage(fileName);
                    if (data != null && data.length > 0) {
                        bm = BitmapFactory.decodeByteArray(data, 0, data.length);
                        imageCache.put(fileName, bm);
                    }
                }
            }
        }
        return bm;
    }

    /**
     * 使用三级缓存为ImageView设置图片
     */
    public void setImageToView(final String path, final ImageView view) {
        final String fileName = path.substring(path.lastIndexOf(File.separator) + 1);
        Bitmap bm = getBitmapFromCache(fileName);
        if (bm != null) {
            view.setImageBitmap(bm);
        } else {
            // 从网络获取图片
            new Thread(new Runnable() {
                @Override
                public void run() {
                    byte[] b = HttpUtil.getInstance().getByteArrayFromWeb(path);
                    if (b != null && b.length > 0) {
                        // 将图片字节数组写入到缓存中
                        putBitmapIntoCache(fileName, b);
                        final Bitmap bm = BitmapFactory.decodeByteArray(b, 0, b.length);
                        // 将从网络获取到的图片设置给ImageView
                        view.post(new Runnable() {
                            @Override
                            public void run() {
                                view.setImageBitmap(bm);
                            }
                        });
                    }
                }
            }).start();
        }
    }
}
    原文作者:成小知
    原文地址: https://www.jianshu.com/p/0b3d4a4409e7
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞