Glide的几个有趣的实现

近期通读了 Glide 框架,阅读过程中发现一些有趣的实现,并且偷师用到了项目中。

生命周期管理

使用 Glide 时,典型的用法是 Glide.with(activity).load(url).into(imageView); 。上述的链式调用中,with() 方法生成 RequestManager,load() 方法生成RequestBuilder。

在 Glide 中,对用户发起的 Request 的生命周期进行管理,是利用 Fragment 的生命周期绑定宿主生命周期这个特性实现的,这里的宿主可以是 Activity 或者 Fragment。生命周期管理的结构如下:

lifecycle

Glide.with() 静态方法被调用时,通过 FragmentManager. findFragmentByTag(FRAGMENT_TAG) 检查宿主是否存在 tag 为 RequestManagerRetriever.FRAGMENT_TAG 的 Fragment ,如果不存在则新建一个 RequestManagerFragment 并且依附到宿主中,

fragmentManager.beginTransaction()
.add(fragment, FRAGMENT_TAG).commitAllowingStateLoss();

然后返回 RequestManagerFragment 的成员属性 RequestManager。

RequestManager.load() 方法调用时生成一个 RequestBuilder,用于配置 Request 的参数,Request 生成后交由 RequestManger 去管理其生命周期(启动/暂停/停止)。

RequestManger 实现了 LifecycleListener 接口,并将自己注册到 ActivityFragmentLifecycle 中,当 RequestManagerFragment 的 onStop() 被调用时,其成员变量 ActivityFragmentLifecycle 的 onStop() 会被调用,所有注册到 ActivityFragmentLifecycle 中的 LifecycleListener(例如 RequestManger)都会得到通知,即可实现监听宿主生命周期的目的。

RequestManagerFragment -> ActivityFragmentLifecycle -> RequestManger -> Request

在使用网络请求类库 OkHttp 时,如果回调中引用了 Fragment 中的 View,就会造成内存泄漏,必须等请求结束(无论是成功还是失败)后才能得到释放。通过这种管理生命周期的方法,可以将 OkHttp 请求与 Fragment 生命周期绑定,为此封装了一个小工具,可以做到Fragment退出时取消网络请求,避免内存泄漏。

线程池切换

在 Glide 中,加载磁盘缓存和加载网络数据是在不同的线程池中执行的,为了讨论方便,加载磁盘缓存的线程池成为 DiskCacheExecutor,加载网络数据的线程池成为 SourceExecutor。

Request 提交到 Engine 之后,会生成一个实现了 Runnable 接口的 DecodeJob,首先会在 DiskCacheExecutor 运行,尝试加载磁盘缓存。如果本地没有缓存,先调用 reschedule(),然后用 return 关键字结束 run() 方法的在 DiskCacheExecutor 的执行。

reschedule() 会将 DecodeJob 重新提交到 SourceExecutor 继续执行,因为在 DiskCacheExecutor 执行的时候改变了 DecodeJob 的 RunReason 属性的值,重新提交到 SourceExecutor 之后会从 DiskCacheExecutor 执行到的位置继续执行。

thread_pool

ps: 为了说明生命周期的控制流程,此前的比较片面,事实上 glide 会考虑到 Fragment 的兼容性,针对不同的系统版本使用 RequestManagerFragment 或 SupportRequestManagerFragment。两者分别继承了android.app.Fragment 与android.support.v4.app.Fragment

评论

退出登录