相比于 LruCache 缓存到内存,这种缓存不会在app退出后又要重新加载数据。因为这种缓存是保存数据到手机文件中,即使app退出后,再次进入app也不用重新加载数据。
代码如下:
/*** 核心: DiskLruCache SD卡缓存* Created by liuyan on 2018/9/10.* 该类用来加载网络图片,并缓存到本地*/
//单例模式
public class SimpleImageLoader {private static int n = 0;private static Context mcontext;private Handler handler = new Handler(Looper.getMainLooper());private static SimpleImageLoader mLoader;private DiskLruCache disklrucache;private static final long MAX_SIZE = 10 * 1024 * 1024;//10MBpublic static SimpleImageLoader getInstance(Context context){mcontext = context;if (mLoader == null){synchronized(SimpleImageLoader.class){if (mLoader == null){mLoader = new SimpleImageLoader();}}}return mLoader;}//用来初始化缓存对象private SimpleImageLoader(){//初始化DiskLruCacheFile cacheDir = getDiskCacheDir(mcontext);if (!cacheDir.exists()) {cacheDir.mkdirs();}try {disklrucache = DiskLruCache.open(cacheDir , 1 , 1 , MAX_SIZE);Log.i("TAG" , disklrucache.getDirectory().getAbsolutePath()+"");} catch (IOException e) {e.printStackTrace();}}public static File getDiskCacheDir(Context context) {//根据有无sd卡,决定缓存的位置final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())? context.getExternalCacheDir().getAbsolutePath(): context.getCacheDir().getAbsolutePath();return new File(cachePath + File.separator + "diskcatchdir");}//用来加载网络图片public void displayImage(ImageView view , String url){Bitmap bitmap = getBitmapFromCatch(url); //if (bitmap != null && view != null){Log.i("TAG" , "从缓存获取");view.setImageBitmap(bitmap);Log.i("TAG" , "结束1");}else {downloadImage(view , url);}}//从缓存中读取图片private Bitmap getBitmapFromCatch(String url){if (url != null){//内存没有,再从本地加载 (这里直接测试本地加载)if (getCache(url) != null){Log.i("TAG" , "从sd卡加载");return getCache(url);}else {Log.i("TAG","sd卡空");}}return null;}private Bitmap getCache(String url) {try {String key = hashKeyForDisk(url);DiskLruCache.Snapshot snapshot = disklrucache.get(key);if (snapshot != null) {InputStream in = snapshot.getInputStream(0);return BitmapFactory.decodeStream(in);}} catch (IOException e) {e.printStackTrace();}return null;}//下载图片,并添加到缓存中去private void downloadImage(final ImageView imageView , final String url){OkHttpClient okHttpClient = new OkHttpClient();final Request request = new Request.Builder().url(url).build();Call call = okHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i("TAG" ,"加载图片失败 " + "所在线程:" + Thread.currentThread().getName());}@Overridepublic void onResponse(Call call, Response response) throws IOException {Log.i("TAG" , "下载图片所在线程:" + Thread.currentThread().getName());//缓存到sd卡String key = hashKeyForDisk(url);DiskLruCache.Editor editor = disklrucache.edit(key);if (editor != null) {Log.i("TAG" ,"第一次加载");int a;OutputStream outputStream = editor.newOutputStream(0);//response已经在上面读取了,再用就没了,所以把上面的注释了InputStream input = response.body().byteStream();while((a = (input.read())) != -1){outputStream.write(a);}editor.commit();Log.i("TAG" , "SD卡缓存成功");}disklrucache.flush();handler.post(new Runnable() {@Overridepublic void run() {displayImage(imageView , url);}});}});}//MD5加密,生成唯一key值public static String hashKeyForDisk(String key) {String cacheKey;try {final MessageDigest mDigest = MessageDigest.getInstance("MD5");mDigest.update(key.getBytes());cacheKey = bytesToHexString(mDigest.digest());} catch (NoSuchAlgorithmException e) {cacheKey = String.valueOf(key.hashCode());}return cacheKey;}private static String bytesToHexString(byte[] bytes) {// http://stackoverflow.com/questions/332079StringBuilder 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();}}
上面代码,要注意到地方有:
1. DiskLruCache 存和取的时候,String key = hashKeyForDisk(url); 一定要经过MD5加密,不然程序可能会崩溃。
2.OKHttp的返回数据,一定要在主线程才能UI操作。不然也会崩溃。
3.记得开启权限:存储和网络
调用如下:
SimpleImageLoader.getInstance(getApplicationContext()).displayImage(imageView , "https://img-my.csdn.net/uploads/201603/26/1458988468_5804.jpg");
打印如下:
1.第一次点击按钮:
09-11 18:03:45.146 18364-18364/com.example.liuyan.bitmapuse I/TAG: sd卡空
09-11 18:03:45.354 18364-19886/com.example.liuyan.bitmapuse I/TAG: 下载图片所在线程:OkHttp https://img-my.csdn.net/...
09-11 18:03:45.355 18364-19886/com.example.liuyan.bitmapuse I/TAG: 第一次加载
09-11 18:03:46.030 18364-19886/com.example.liuyan.bitmapuse I/TAG: SD卡缓存成功
09-11 18:03:46.042 18364-18364/com.example.liuyan.bitmapuse I/TAG: 从sd卡加载
09-11 18:03:46.051 18364-18364/com.example.liuyan.bitmapuse I/TAG: 从缓存获取
09-11 18:03:46.051 18364-18364/com.example.liuyan.bitmapuse I/TAG: 结束1
2.退出app后再次进入,再点击按钮:
09-11 18:03:54.863 18364-18364/com.example.liuyan.bitmapuse I/TAG: 从sd卡加载
09-11 18:03:54.871 18364-18364/com.example.liuyan.bitmapuse I/TAG: 从缓存获取
09-11 18:03:54.872 18364-18364/com.example.liuyan.bitmapuse I/TAG: 结束1
从打印可看出,即使退出了,也没有问题.