Android图片缓存加强版(LruCache+DiskLruCache+软引用)

将LruCache+DiskLruCache+软引用三种缓存技术结合起来,加强图片的缓存效果。

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.support.v4.util.LruCache;

import com.jakewharton.disklrucache.DiskLruCache;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;

public class ImageCache {
    private static final String IMAGE_PATH = "image";
    private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 8;
    private static final int DEFAULT_DIS_CACHE_SIZE = 1024 * 1024 * 10;
    private static final int DEDAULT_SOFT_CACHE_NUM = 20;

    private LruCache<String, Bitmap> mLruCache;
    private DiskLruCache mDisLruCache;
    private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;

    private volatile static ImageCache mImageCache;

    private ImageCache(Context context) {
        mLruCache = new LruCache<String,Bitmap>(DEFAULT_MEM_CACHE_SIZE) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return getBitmapSize(value);
            }

            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                if (evicted) {
                    mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
                }
                super.entryRemoved(evicted, key, oldValue, newValue);
            }
        };

        try {
            mDisLruCache.open(getDiskCacheDir(context), getAppVersion(context), 1, DEFAULT_DIS_CACHE_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }


        mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
                DEDAULT_SOFT_CACHE_NUM, 0.75f, true) {
            private static final long serialVersionUID = 1L;
            /**
             * 当软引用数量大于20的时候,最旧的软引用将会被从链式哈希表中移出
             */
            @Override
            protected boolean removeEldestEntry(
                    Entry<String, SoftReference<Bitmap>> eldest) {
                if (size() > DEDAULT_SOFT_CACHE_NUM) {
                    return true;
                }
                return false;
            }
        };

    }

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

    /*
    * 查看缓存是否存在key的图片,
    * 在从网络获取图片之前可以先进行查看,如果没有就网络请求
    *
    * 策略:先查看mLruCache是否存在该实例对象,即查看内存是否存在该对象
    *      再查看mSoftCache是否存在,即查看mLruCache中被回收的对象中是否存在该对象
    *      最后查看Disk中是否缓存了该对象
    * 
    * */
    public Bitmap get(String key) {
        key = hashKey(key);

        DiskLruCache.Snapshot snapshot = null;
        Bitmap bitmap = mLruCache.get(key);

        if (bitmap == null) {
            bitmap = mSoftCache.get(key).get();

            if (bitmap == null) {
                if (mDisLruCache != null) {
                    try {
                        snapshot = mDisLruCache.get(key);

                        if (snapshot != null) {
                            InputStream is = snapshot.getInputStream(0);
                            bitmap = BitmapFactory.decodeStream(is);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                mSoftCache.remove(key);
            }

            if (bitmap != null) {
                mLruCache.put(key, bitmap);
            }
        }

        return bitmap;
    }

    /*
    * 从网络获取到图片资源之后,就调用该方法将它进行缓存,
    * */
    public void put(String key, Bitmap bitmap) {
        key = hashKey(key);

        mLruCache.put(key, bitmap);

        if (mDisLruCache != null) {
            try {
                DiskLruCache.Editor editor = mDisLruCache.edit(key);

                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(0);
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
                    outputStream.write(byteArrayOutputStream.toByteArray());
                    editor.commit();
                    mDisLruCache.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    * 获取图片大小
    * */
    private int getBitmapSize(Bitmap bitmap) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return bitmap.getByteCount();
        }
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /*
    * 得到Disk缓存目标
    * */
    private File getDiskCacheDir(Context context) {
        String cachePath;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }

        return new File(cachePath + File.separator + IMAGE_PATH);
    }

    /*
    * 获取应用版本号
    * */
    private int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /*
    * 将key编码为MD5
    * */
    private String hashKey(String key) {
        String cacheKey;

        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.update(key.getBytes());
            cacheKey = bytesToHexString(digest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
            e.printStackTrace();
        }
        return cacheKey;

    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}

参考文章:
Android图片缓存技术

android中图片的三级cache策略(内存、文件、网络)之二:内存缓存策略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值