Glide 图片库原理(二)
Glide 吐槽
源码太多了,状态机对于阅读源码来说是个苦力活,而且必须借助工具完成,推荐脑图
简化一个整个流程图
Glide整体简化图.pngwith, load ,into
into 代码巨大,先上流程图
Glide.width 流程图
Gilde_with.pnginto 流程图
Glide_into .png由于代码流程太多,所以建议下载图片放大看细节。
或者跟着脑图走--->Github docs 放在vscode 插件中查看
分析源码思路,
第一大步:只管主线 简单的走通 不要管支线
第二大步:重点在主线,稍微瞄一眼支线
第三大步:稍微分析支线,回顾主线
第四大步:分析支线细节,回顾主线
第五大步:分析支线细节,来寻找答案
0.项目中大量的使用了Glide,偶尔会出现内存溢出问题,请说说大概是什么原因?
答:尽量在with的时候,传入有生命周期的作用域(非Application作用域),尽量避免使用了Application作用域,因为Application作用域不会对页面绑定生命周期机制,就回收不及时释放操作等....
1.使用Glide为什么要加入网络权限? <uses-permission android:name="android.permission.INTERNET" />
答:等待队列/运行队列 执行Request ---> 活动缓存 --->内存缓存 ---> jobs.get检测执行的任务有没有执行完成 ---> HttpUrlFetcher.HttpURLConnection
2.使用Glide时,with函数在子线程中,会有什么问题?
答:子线程,不会去添加 生命周期机制, 主线程才会添加 空白的Fragment 去监听 Activity Fragment 的变化。
3.使用Glide时,with函数传入Application后,Glide内部会怎么处理?
答:在MainActivity中,MainActivity销毁了,并会让Glide生命周期机制处理回收,只有在整个APP应用都没有的时候,跟随着销毁(上节课 ApplicationLIfecycle add onStart onDestroy 什么事情都没有做)。
4.Glide源码里面的缓存,为什么要有 活动缓存 还需要 有内存缓存?
答:
因为LRU内存缓存添加满的时候,刚好访问最少使用那个A,如果LRU在添加数据,那么就会移除A,但是界面正在用A,那么就会导致崩溃。为了解决这种问题,所以添加了活动缓存。
把正在使用的放在活动缓存中,并且是非LRU的缓存。
分析步骤
第一步:【with】
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
// Application 作用域
} else {
// 非Application 作用域
}
}
第二步:【load】
最终返回:RequestBuilder
第三步:【into】 看源码的思路,如果遇到接口怎么办? 前面必须 埋下伏笔
1. ImageViewTarget(显示图片) 无论走多远多远,最终一定回到这里ImageViewTarget 埋下伏笔
return into(
glideContext.buildImageViewTarget(view, transcodeClass), ImageViewTarget
);
2. Request request = new SingleRequest 埋下伏笔
3. SingleRequest public void begin() {...}
4. if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight); 用户设置 宽和高
} else {
target.getSize(this); 用户没有设置 宽和高 再次测量 -----> onSizeReady
}
5. memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); 活动缓存 内存缓存
if (memoryResource == null) {
缓存没有
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE); 命中缓存 回调去显示了
6. EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); 查找有没有正在运行的任务
7. EngineJob线程池大管家 DecodeJob执行的任务
8. currentGenerator = getNextGenerator(); SourceGenerator 埋下伏笔
9. SourceGenerator 分析 LoadData<Data> buildLoadData 没有埋下伏笔 Glide预习资料(构造函数 注册机)
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory()) Glide 注册机 埋下了伏笔
List<LoadData<?>> getLoadData() == HttpGlideUrlLoader {目标HttpUrlFetcher}
最终返回:HttpUrlFetcher 终于找到了 网络访问的地方 HttpUrlConn 来得到 InputStream
10 public Resource<Transcode> decode(
{
// InputStream ---> Bitmap == decoded
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); // 回调回去
return transcoder.transcode(transformed, options);
}