glide缓存机制 android,Glide 缓存原理实现

Glide 缓存原理实现

专注于Android开发,分享经验总结,欢迎加入

QQ群:686809487

Glide使用方式如下:

Glide.with(MainActivity.this)

.load(path)

.into(iv);

Glide缓存分为:活动缓存、内存缓存、Bitmap复用池、磁盘缓存、加载外置(网络或者SD卡)、绑定生命周期

具体的流程如下

1212d7bbbc4c

在这里插入图片描述

资源封装

Key -- 对Value的唯一性进行描述

Value -- 对Bitmap的封装

活动缓存

// 用容器存储

private HashMap> map = new 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 treeMap = new 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

// 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);

日志记录

1212d7bbbc4c

image

源码查看,关注公众号回复 Glide ,获取

微信公众号 -->> 他晓 (欢迎加入)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值