专注于Android开发,分享经验总结,欢迎加入
Glide使用方式如下:
Glide.with(MainActivity.this)
.load(path)
.into(iv);
Glide缓存分为:活动缓存、内存缓存、Bitmap复用池、磁盘缓存、加载外置(网络或者SD卡)、绑定生命周期
具体的流程如下
资源封装
Key – 对Value的唯一性进行描述
Value – 对Bitmap的封装
活动缓存
// 用容器存储
private HashMap
// 继承WeakReference(目的:为了监听这个弱引用 是否被回收了)
public class CustomWeakReference extends WeakReference {
public String key;
public CustomWeakReference(Object referent, ReferenceQueue queue, String key) {
super(referent, queue);
this.key = key;
}
}
/**
* 目的:为了监听这个弱引用 是否被回收了
* queue.remove() 会阻塞线程
*
* @return
*/
public ReferenceQueue getQueue() {
if (queue == null) {
queue = new ReferenceQueue<>();
// 监听这个弱引用 是否被回收了
thread = new Thread() {
@Override
public void run() {
while (!isCloseThread) {
if (!isShoudonRemove) {
try {
// 阻塞式的方法,被动调用queue.remove(),进行回收
Reference extends Value> remove = queue.remove();
CustomWeakReference customWeakReference = (CustomWeakReference) remove;
if (map != null && !map.isEmpty()) {
// 移除容器 !isShoudonRemove:为了区分手动移除 和 被动移除
map.remove(customWeakReference.key);
}
Log.d(TAG, "getQueue remove ");
} catch (InterruptedException e) {
Log.d(TAG, "getQueue InterruptedException e :" + e.getMessage());
e.printStackTrace();
}
}
}
}
};
thread.start();
}
return queue;
}
当活动缓存的值不在被使用时,从活动缓存移除,并加入都内存缓存
内存缓存
内存缓存 使用 Lru算法,继承自 LruCache
重写sizeOf(),entryRemoved()方法监听元素被移除
@Override
protected int sizeOf(@NonNull String key, @NonNull Value value) {
Bitmap bitmap = value.getBitmap();
// 最开始的时候
// int result = bitmap.getRowBytes() * bitmap.getHeight();
// API 12 3.0
// result = bitmap.getByteCount(); // 在bitmap内存复用上有区别 (所属的)
// API 19 4.4
// result = bitmap.getAllocationByteCount(); // 在bitmap内存复用上有区别 (整个的)
return Tool.getBitmapByteSize(bitmap);
}
/**
* 被移除时监听
* 1.重复的key
* 2.最少使用的元素会被移除
*
* @param evicted
* @param key
* @param oldValue
* @param newValue
*/
@Override
protected void entryRemoved(boolean evicted, String key, Value oldValue, Value newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
// !shoudonRemove == 被动的
if (memoryCacheCallback != null && !shoudonRemove) {
memoryCacheCallback.entryRemovedMemoryCache(key, oldValue);
}
}
当内存缓存移除最少使用值的时候,加入到BitmapPool复用池(复用Bitmap地址,避免频繁调用内存空间,防止内存抖动、内存碎片)
Bitmap复用池
LruBitmapPool extends LruCache
使用容器TreeMap
重写put()和get()方法,加入存取的一些条件
@Override
public void put(Bitmap bitmap) {
Tool.checkNotEmpty(bitmap);
// TODO 复用的条件1 bitmap.isMutable()
if (!bitmap.isMutable()) {
if (!bitmap.isRecycled()) {
bitmap.recycle();
Log.d(TAG, "put: 复用的条件1 Bitmap.ismutable 是false,条件不满足,不能复用 添加..." + bitmap);
return;
}
}
// TODO 复用的条件2 如果添加复用的Bitmap大小,大于Lru MaxSize 就不复用
int bitmapByteSize = Tool.getBitmapByteSize(bitmap);
if (bitmapByteSize > maxSize()) {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
Log.d(TAG, "put: 复用的条件2 Bitmap.Size大于LruMaxSize,条件不满足,不能复用 添加...");
return;
}
// 添加到 Lru Cahce中去
put(bitmapByteSize, bitmap);
// 保存到 TreeMap 是为了筛选
treeMap.put(bitmapByteSize, null);
Log.d(TAG, "put: 添加到复用池了....");
}
@Override
public Bitmap get(int width, int height, Bitmap.Config config) {
if (treeMap.isEmpty()) {
Log.d(TAG, "treeMap:为空");
return null;
}
// config为null 默认给 Bitmap.Config.ARGB_8888
int bitmapByteSize = Tool.getBitmapByteSize(width, height, config);
// TODO ceilingKey 获得 getSize这么大的key,同时还可以获得 比 getSize还要大的key
Integer key = treeMap.ceilingKey(bitmapByteSize);// 获得 getSize这么大的key,同时还可以获得 比 getSize还要大的key
if (key == null) {
Log.d(TAG, "treeMap:找不到 保存的key");
return null; // 如果找不到 保存的key,就直接返回null,无法复用
}
// 找出来的key 小于等于 (getSize * 2)
if (key <= (bitmapByteSize * 2)) {
Bitmap resultBitmap = remove(key);
Log.d(TAG, "get: 从复用池获取:" + resultBitmap);
return resultBitmap;
}
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inBitmap = bitmapPoolResult;// bitmapPoolResult为null,不复用地址,复用Bitmap地址,避免频繁调用内存空间,防止内存抖动、内存碎片
磁盘缓存
使用JakeWharton开源项目DiskLruCache
https://github.com/JakeWharton/DiskLruCache
// TODO put 存入Value
public void put(String key, Value value) {
Tool.checkNotEmpty(key);
OutputStream outputStream = null;
DiskLruCache.Editor edit = null;
try {
edit = diskLruCache.edit(key);
// index 不能大于 VALUE_COUNT
outputStream = edit.newOutputStream(0);
// 把bitmap写入到outputStream
Bitmap bitmap = value.getBitmap();
if (bitmap != null) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
try {
// Aborts this edit. This releases the edit lock so another edit may be
// 中止此编辑。 这会释放编辑锁,因此可能需要进行其他编辑
if (edit != null) {
edit.abort();
}
} catch (IOException ex) {
ex.printStackTrace();
Log.e(TAG, "put: editor.abort(); e:" + ex.getMessage());
}
} finally {
try {
if (edit != null) {
edit.commit();
}
diskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "put: editor.commit(); e:" + e.getMessage());
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "put: outputStream.close(); e:" + e.getMessage());
}
}
}
}
// TODO get 获取Value
public Value get(String key, BitmapPool bitmapPool) {
InputStream inputStream = null;
try {
DiskLruCache.Snapshot snapshot = diskLruCache.get(key);
// 判断快照不为null的情况下,在去读取操作
if (snapshot != null) {
// index 不能大于 VALUE_COUNT
inputStream = snapshot.getInputStream(0);
// 复用Bitmap地址,避免频繁调用内存空间,防止内存抖动、内存碎片
Bitmap bitmap = Tool.getIOBitmap(inputStream, bitmapPool, true);
Value value = Value.getInstance();
value.setKey(key);
value.setBitmap(bitmap);
return value;
}
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "get: IOException; e:" + e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "get: inputStream.close(); e:" + e.getMessage());
}
}
}
return null;
}
生命周期
.with(Context) 与当前的上下文绑定;通过上下文绑定一个Fragment实现管理生命周期
Context分为:
Application无法绑定生命周期
FragmentActivity 可绑定生命周期
Activity 可绑定生命周期
public interface LifecycleCallback {
// 生命周期初始化了
public void glideInitAction();
// 生命周期 停止了
public void glideStopAction();
// 生命周期 释放 操作了
public void glideRecycleAction();
}
网络加载/SD卡加载
网络加载:开一个线程池去加载,通过HttpConnection
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque());
threadPoolExecutor.execute(this);
开子线程去加载
@Override
public void run() {
InputStream inputStream = null;
HttpURLConnection httpURLConnection = null;
try {
URL url = new URL(path);
URLConnection urlConnection = url.openConnection();
httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setReadTimeout(5000);
final int responseCode = httpURLConnection.getResponseCode();
if (HttpURLConnection.HTTP_OK == responseCode) {
inputStream = httpURLConnection.getInputStream();
// 复用Bitmap地址,避免频繁调用内存空间,防止内存抖动、内存碎片
final Bitmap bitmap = Tool.getIOBitmap(inputStream, null, false);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Value value = Value.getInstance();
value.setBitmap(bitmap);
responseListener.responseSuccess(value);
}
});
} else {
// 失败 切换主线程
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
responseListener.responseException(new IllegalStateException("请求失败 请求码:" + responseCode));
}
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
e.printStackTrace();
Log.d(TAG, "run: 关闭 inputStream.close(); e:" + e.getMessage());
}
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}
SD卡加载:
Bitmap bitmap = BitmapFactory.decodeFile(path);
Value value = Value.getInstance();
value.setBitmap(bitmap);
// 回调成功
Log.d(TAG, " LoadDataManager 从本地获取到bitmap");
responseListener.responseSuccess(value);
源码查看,关注公众号回复 Glide ,获取
微信公众号 -->> 他晓 (欢迎加入)