标签:src draw target bitmap tin cat hash 构建 pre
一、概述
在分析OkHttp3的缓存机制之前先手写一个实现了三级缓存的ImageLoader来整体感受一下LruCache和DiskLruCache的用法。本例实现了三级缓存,利用LruCache实现内存缓存,利用DiskLruCache实现磁盘缓存。整体的流程是:当用户请求一张图时,首先检查内存中是否有缓存图片,如果有就直接返回,如果没有就检查磁盘中是否有,有就返回,没有就启用网络下载图片,然后把图片缓存在磁盘缓存和内存缓存中。下面看看具体的实现步骤。
二、源程序介绍
1.ImageLoader.java:是一个单例类,是加载图片的入口.
2.CacheManager.java用来管理LruCacheManger和DiskLruCacheManager
3.LruCacheManager.java是用来管理内存缓存的。
4.DiskLruCacheManager是用来管理磁盘缓存的
5.DownloadFileUtil.java是用来下载文件的,本例指的是图片
6.MainThreadHandler.java是创建了一个运行在主线程中的Handler
7.Util.java工具类
8.MsgConfig.java配置类
9.LoaderResult.java存储view、bitmap和uri的工具类
10.ImageResizer.java用来缩放图片用的
整体类图结构

ImageLoader.java中就放了一个线程池(自定义线程池)外加displayView显示方法
public class ImageLoader {
private ImageLoader(Context context) {
mainThreadHandler = new MainThreadHandler();
cacheManager = new CacheManager(context, THREAD_POOL_EXECUTOR, mainThreadHandler);
}
private static final String TAG = "ImageLoader";
public static final int MESSAGE_POST_RESULT = 1;
//核心Cpu数量
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//核心线程数量
//线程池的最大容量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final long KEEP_ALIZE = 10l;
private static final ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ImageLoader#" + mCount.getAndIncrement());
}
};
//创建一个线程池
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIZE, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(), threadFactory);
private Context context;
private CacheManager cacheManager;
private MainThreadHandler mainThreadHandler;
private static ImageLoader imageLoader = null;
public static ImageLoader getDefault(Context context) {
synchronized (ImageLoader.class){
if(imageLoader==null){
imageLoader = new ImageLoader(context);
}
}
return imageLoader;
}
/**
* 异步加载一张图片并显示在view上
*
* @param url
* @param view
*/
public void displayView(String url, View view) {
cacheManager.bindBitmap(url, view);
}
/**
* 根据url获取一个bitmap
*
* @param url
* @param reqWidth
* @param reqHeight
* @return
*/
public Bitmap getBitmap(String url, int reqWidth, int reqHeight) {
return cacheManager.loadBitmap(url, reqWidth, reqHeight);
}
/**
* 异步加载指定图片的大小加载图片
*
* @param url
* @param view
* @param reqWidth
* @param reqHeight
*/
public void displayView(String url, View view, int reqWidth, int reqHeight) {
cacheManager.bindBitmap(url, view, reqWidth, reqHeight);
}
}
CacheManager.java用来管理磁盘缓存 和内存缓存,并实现三级缓存的判断
package com.yw.library;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Looper;
import android.os.StatFs;
import android.util.LruCache;
import android.view.View;
import android.widget.ImageView;
import com.jakewharton.disklrucache.DiskLruCache;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 缓存管理类
* create by yangwei
* on 2020-03-01 22:13
*/
public class CacheManager {
private ImageResizer imageResizer = new ImageResizer();
private Executor THREAD_POOL_EXECUTOR;
//磁盘缓存的最大容量
public static final long DISK_CACHE_SIZE = 1024 * 1024 * 50;
public static final int DISK_CACHE_INDEX = 0;
private LruCacheManager lruCacheManager;
private DiskLruCacheManager diskLruCacheManager;
private MainThreadHandler mainThreadHandler;
private Context context;
public CacheManager(Context context,Executor THREAD_POOL_EXECUTOR,MainThreadHandler mainThreadHandler) {
this.THREAD_POOL_EXECUTOR = THREAD_POOL_EXECUTOR;
this.mainThreadHandler = mainThreadHandler;
this.context = context;
lruCacheManager = new LruCacheManager();
diskLruCacheManager = new DiskLruCacheManager(context,imageResizer,lruCacheManager);
}
public void bindBitmap(final String uri, final View view) {
bindBitmap(uri, view, 0, 0);
}
public void bindBitmap(final String uri, final View view, final int reqWidth, final int reqHeight) {
view.setTag(MsgConfig.TAG_KEY_URI, uri);
Bitmap bitmap = loadBitmapFromMemoryCache(uri);
if (bitmap != null) {
if (view instanceof ImageView) {
((ImageView) view).setImageBitmap(bitmap);
} else {
view.setBackground(new BitmapDrawable(bitmap));
}
return;
}
//利用线程池在后台加载图片,加载成功后进入主线程更新UI
THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
Bitmap bitmap = loadBitmap(uri, reqWidth, reqHeight);
LoaderResult loaderResult = new LoaderResult(view, uri, bitmap);
//向主线程中发送loaderresult
mainThreadHandler.obtainMessage(MsgConfig.MESSAGE_POST_RESULT, loaderResult).sendToTarget();
}
});
}
public Bitmap loadBitmap(String uri, int reqWidth, int reqHeight) {
Bitmap bitmap = loadBitmapFromMemoryCache(uri);
if (bitmap != null) {
return bitmap;
}
bitmap = diskLruCacheManager.loadBitmapFromDiskCache(uri, reqHeight, reqHeight);
if (bitmap != null) {
return bitmap;
}
bitmap = loadBitmapFromHttp(uri, reqWidth, reqHeight);
if (bitmap != null) {
return bitmap;
}
if (bitmap == null && !diskLruCacheManager.mIsDiskLruCacheCreated) {
bitmap = DownloadFileUtil.get().downloadBitmapFromUrl(uri);
}
return bitmap;
}
private Bitmap loadBitmapFromMemoryCache(String url) {
final String key = Util.hashKeyFromUrl(url);
Bitmap bitmap = lruCacheManager.getBitmapFromMemoryCache(key);
return bitmap;
}
private Bitmap loadBitmapFromHttp(String url, int reqWidth, int reqHeight) {
diskLruCacheManager.addBitmapToDiskCache(url);
return diskLruCacheManager.loadBitmapFromDiskCache(url, reqWidth, reqHeight);
}
public static class Builder {
public Builder(){}
}
}
LruCacheManager.java用来管理LruCache
package com.yw.library;
import android.graphics.Bitmap;
import android.util.LruCache;
/**
* create by yangwei
* on 2020-03-01 22:30
*/
public class LruCacheManager {
private LruCache<String, Bitmap> mMemoryCache = null;
public LruCacheManager() {
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//返回bitmap的大小,单位是kb
return value.getRowBytes() * value.getHeight() / 1024;
}
};
}
/**
* 相内存缓存中添加一个Bitmap
*
* @param key
* @param bitmap
*/
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemoryCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
/**
* 从内存缓存中取出一个Bitmap
*
* @param key
* @return
*/
public Bitmap getBitmapFromMemoryCache(String key) {
return mMemoryCache.get(key);
}
}
DissLruCacheManager用来管理DiskLruCache
package com.yw.library;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Looper;
import android.os.StatFs;
import com.jakewharton.disklrucache.DiskLruCache;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.OutputStream;
/**
* 磁盘缓存管理
* create by yangwei
* on 2020-03-01 22:30
*/
public class DiskLruCacheManager {
private DiskLruCache mDiskLruCache = null;
private Context context;
public boolean mIsDiskLruCacheCreated = false;
private ImageResizer imageResizer;
private LruCacheManager lruCacheManager;
/**
* 初始化参数
*
* @param context
* @param imageResizer
* @param lruCacheManager
*/
public DiskLruCacheManager(Context context, ImageResizer imageResizer, LruCacheManager lruCacheManager) {
this.context = context;
this.imageResizer = imageResizer;
this.lruCacheManager = lruCacheManager;
//创建磁盘缓存路径
File diskCacheDir = FileUtil.createDiskCacheDir(context, "bitmap");
if (!diskCacheDir.exists()) {
diskCacheDir.mkdirs();
}
if (getUsableSpace(diskCacheDir) > CacheManager.DISK_CACHE_SIZE) {
try {
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, CacheManager.DISK_CACHE_SIZE);
mIsDiskLruCacheCreated = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 添加Bitmap到磁盘
*
* @param url
*/
public void addBitmapToDiskCache(String url) {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new RuntimeException("can not visit network form Ui Thread");
}
try {
String key = Util.hashKeyFromUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(CacheManager.DISK_CACHE_INDEX);
if (DownloadFileUtil.get().downloadUrlToStream(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
mDiskLruCache.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从磁盘中加载图片
*
* @param url
* @param reqWidth
* @param reqHeight
* @return
*/
public Bitmap loadBitmapFromDiskCache(String url, int reqWidth, int reqHeight) {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new RuntimeException("can not load bitmap from UI Thread");
}
if (mDiskLruCache == null) {
return null;
}
Bitmap bitmap = null;
try {
String key = Util.hashKeyFromUrl(url);
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot != null) {
FileInputStream fileInputStream = (FileInputStream) snapshot.getInputStream(CacheManager.DISK_CACHE_INDEX);
FileDescriptor fileDescriptor = fileInputStream.getFD();
bitmap = imageResizer.decodeBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight);
try {
if (bitmap.getHeight() > 0) {
if (bitmap != null) {
lruCacheManager.addBitmapToMemoryCache(key, bitmap);
}
}
} catch (Exception e) {
return null;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
public long getUsableSpace(File path) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return path.getUsableSpace();
}
final StatFs statFs = new StatFs(path.getPath());
return statFs.getBlockSizeLong() * statFs.getAvailableBlocksLong();
}
}
总结:整体逻辑的构建基本上都在CacheManager中,逻辑还是比较清楚的。
ps:完整代码在github,有需要的可以去下载。下载路径如下:
使用LruCache和DiskLruCache手写一个ImageLoader
标签:src draw target bitmap tin cat hash 构建 pre
原文地址:https://www.cnblogs.com/tony-yang-flutter/p/12394761.html