写了这个我也不会用在自己项目中,因为是Glide它不香了还是Fresco不好用??前面说下需要了解的一些知识,后面全是代码。
首先,图片编码:
- ALPHA_8 图片只有alpha值,没有RGB值,一1个像素占用一个字节
- ARGB_4444 alpha(A)值,Red(R)值,Green(G)值,Blue(B)值各占4个bites共16bites,2个字节
- ARGB_8888 alpha(A)值,Red(R)值,Green(G)值,Blue(B)值各占8个bites,共32bites,4个字节。
- RGB_565 没有alpha(A)值,不支持透明和半透明,Red(R)值占5个bites ,Green(G)值占6个bites ,Blue(B)值占5个bites,共16bites,2个字节。
基本上常用的就这些。系统默认的是ARGB_8888也就是默认一个像素点4字节,不需要透明度的时候可以手动切成RGB_565。
LruCache原理
简而言之就是内部维护了一个双向链表,LinkedHashMap。会先设定一个缓存大小,一般为可用内存的八分之一。如果有新数据插入,会把新数据插到队尾,所以头部的数据就是最近最少使用的数据。插入之后如果内存大小超过限制了,那就会移除头部元素。
InBitmap
需要事先设置Inmutable为true。Inmutable是表示这个bitmap的内存大小可变。我们用Bitmap工厂创建一个Bitmap后,都会从内存获得一块空间。InBitmap就是让后面的Bitmap直接复用之前的Bitmap空间,所以这个内存空间大小必须是可以变动的才行。
但是使用有很多限制,官网上有直接给出代码,抄就行了。
- 4.4之前的版本inBitmap只能够重用相同大小的Bitmap内存区域。简单而言,被重用的Bitmap需要与新的Bitmap规格完全一致,否则不能重用。
- 4.4之后的版本系统不再限制旧Bitmap与新Bitmap的大小,保证旧Bitmap的大小是大于等于新Bitmap大小即可。
- 旧Bitmap必须是mutable的
三级缓存
- 首次加载的时候通过网络加载,获取图片,然后保存到内存和 SD 卡中。
- 运行 APP 时,优先访问内存中的图片缓存。
- 如果内存没有,则加载本地 SD 卡中的图片。
内存->磁盘->网络。加载速度和顺序就是这样。
磁盘缓存
DiskLruCache,直接在GitHub上可以下载到,也算是google官方推荐的。剩下的直接上代码了。
/**
*/
public class ImageManager {
//磁盘缓存
private DiskLruCache diskLruCache;
private LruCache<String, Bitmap> lruCache;
//复用池
private Set<SoftReference<Bitmap>> reusableBitmaps;
//引用队列
private ReferenceQueue<Bitmap> referenceQueue;
//取出线程
private Thread clearThread;
private static volatile ImageManager imageManager;
public static ImageManager getInstance() {
if (imageManager == null) {
synchronized (ImageManager.class) {
if (imageManager == null) {
imageManager = new ImageManager();
}
}
}
return imageManager;
}
public void init(Context context) {
ActivityManager am = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
lruCache = new LruCache<String, Bitmap>(am.getMemoryClass() / 8 * 1024 * 1024) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
if (oldValue.isMutable()) {
reusableBitmaps.add(new SoftReference<Bitmap>(oldValue, referenceQueue));
} else {
oldValue.recycle();
}
}
};
reusableBitmaps =
Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
clearThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Reference remove = referenceQueue.remove();
Bitmap bitmap = (Bitmap) remove.get();
if (bitmap != null) {
bitmap.recycle();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
clearThread.start();
referenceQueue = new ReferenceQueue();
File file = getDiskCacheDir(context, "thumb");
try {
diskLruCache = DiskLruCache.open(file, BuildConfig.VERSION_CODE, 1,
10 * 1024 * 1024);
} catch (IOException e) {
}
}
/**
* 写进内存
*
* @param key
* @param bitmap
*/
public void putToMemory(String key, Bitmap bitmap) {
lruCache.put(key, bitmap);
}
/**
* 从复用池获取
*/
public Bitmap getFromPool() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB) {
return null;
}
Bitmap getInBitmap = null;
Iterator<SoftReference<Bitmap>> iterator = reusableBitmaps.iterator();
while (iterator.hasNext()) {
SoftReference<Bitmap> next = iterator.next();
Bitmap bitmap = next.get();
if (bitmap != null) {
getInBitmap = bitmap;
break;
}
}
return getInBitmap;
}
/**
* 从内存获取
*
* @param key
* @return
*/
public Bitmap getFromMemory(String key) {
return lruCache.get(key);
}
/**
* 写入磁盘的方法
*
* @param key
* @param bitmap
*/
public void putToDisk(String key, Bitmap bitmap) {
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = diskLruCache.get(key);
//如果磁盘没有文件,写入
if (snapshot == null) {
DiskLruCache.Editor edit = diskLruCache.edit(key);
OutputStream outputStream = edit.newOutputStream(0);
bitmap.compress(Bitmap.CompressFormat.JPEG, 0, outputStream);
edit.commit();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (snapshot != null) {
snapshot.close();
}
}
}
BitmapFactory.Options options = new BitmapFactory.Options();
public Bitmap getFromDisk(String key, Bitmap bitmap) {
Bitmap diskBitmap = null;
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = diskLruCache.get(key);
if (snapshot == null) {
return null;
}
InputStream inputStream = snapshot.getInputStream(0);
options.inMutable = true;
options.inBitmap = bitmap;
diskBitmap=BitmapFactory.decodeStream(inputStream, null, options);
putToMemory(key, diskBitmap);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (snapshot != null) {
snapshot.close();
}
}
return diskBitmap;
}
public void clearAll() {
lruCache.evictAll();
}
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}
}
这就是三级缓存的管理类,从内存到磁盘。要注意的地方不多,大部分地方也加上了注释。缺陷点的地方就是InBitmap的使用。
如果有什么不对的地方可以在评论区指出谢谢。