博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【笔记整理】Glide 4.9.0 关于监听生命周期
阅读量:3566 次
发布时间:2019-05-20

本文共 10408 字,大约阅读时间需要 34 分钟。

在 中说过,对于 with() 方法传递的参数(包括 ActivityFragmentView 等),如果对应的 context 为非 Application 类型的,Glide 会为作为参数传递进with() 方法的 Activity 或者 Fragment 添加一个隐藏的且隐藏的(即没有 UI 的) FragmentSupportRequestManagerFragment 或者 RequestManagerFragment 类型),用以监测 Activity 或者 Fragment 的生命周期,如果起被销毁,则 Glide 是可以感知到的,从而停止加载图片到指定的 View 中。

对于 SupportRequestManagerFragmentRequestManagerFragment 在实现原理上类似,只不过是因为 v4 包的原因而分别实现的。下面以 SupportRequestManagerFragment 为例子。

// RequestManagerRetriever.javaprivate RequestManager supportFragmentGet(    @NonNull Context context,    @NonNull FragmentManager fm,    @Nullable Fragment parentHint,    boolean isParentVisible) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); // 构建一个新的 RequestManager requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager;}private SupportRequestManagerFragment getSupportRequestManagerFragment( @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) {
// 先从 pendingSupportRequestManagerFragments 中去获取 current = pendingSupportRequestManagerFragments.get(fm); if (current == null) {
// 获取不到的话在 new 一个新的 current = new SupportRequestManagerFragment(); current.setParentFragmentHint(parentHint); if (isParentVisible) {
current.getGlideLifecycle().onStart(); } // 然后暂时缓存到 pendingSupportRequestManagerFragments 中 pendingSupportRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); // 等到被 fm 添加后再移除 handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current;}

supportFragmentGet() 方法主要是为了获取 FragmentManager fm 对应的 requestManager。而 requestManager 是被存储经由 fm 添加的 SupportRequestManagerFragment 中的。

因此首先根据 fm 来获取对应的 SupportRequestManagerFragment。而具体的逻辑是在 getSupportRequestManagerFragment() 中实现的。

getSupportRequestManagerFragment() 中会先根据 TAG 从 fm 中去获取对应的 SupportRequestManagerFragment 实例。如果还没有被添加,会先 new 一个新的并添加。

注意一个细节,在 getSupportRequestManagerFragment() 中,会先从 pendingSupportRequestManagerFragments 中去获取目标 SupportRequestManagerFragment,如果没有才会 new 一个新的,然后又会先缓存到 pendingSupportRequestManagerFragments 中,等到被 fm 添加之后,才会通过 handler发送 msg 去移除。这里的目的应该是为了防止被 fm 重复添加。

然后再回到 supportFragmentGet() 方法中,当通过 getSupportRequestManagerFragment() 获得对应的 SupportRequestManagerFragment 后,如果其是新 new 的,则此时调用 SupportRequestManagerFragment#getRequestManager() 得到的值就会为 null,因此需要构建一个新的 RequestManager 并设置到 SupportRequestManagerFragment 中。

划重点 :可以看到,在构建 RequestManager 的时候会传入 SupportRequestManagerFragment 的成员变量 lifecycle(具体为 ActivityFragmentLifecycle 类型)。

// RequestManager 的构造方法RequestManager(    Glide glide,    Lifecycle lifecycle,    RequestManagerTreeNode treeNode,    RequestTracker requestTracker,    ConnectivityMonitorFactory factory,    Context context) {
... connectivityMonitor = factory.build( context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); // addSelfToLifecycle 实现在主线程中调用 lifecycle.addListener(this); if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle); } else {
lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); ...}

然后在 RequestManager 的构造方法中(即构建它的时候),会将自身添加到 ActivityFragmentLifecyclelifecycleListeners 集合中。以及会将 connectivityMonitor 也添加进去。

这样做的目的就是为了与 SupportRequestManagerFragment 的生命周期实现关联。(具体的原理在后文)

而且,需要知道的是,RequestManagerSupportRequestManagerFragment 是一一对应的关系,因此,尽管在一个业务 Activity 中,可能会存在多次调用 Glide 来加载图片,但是只会存在一个 RequestManager,只不过多次调用会产生多个 Request,而该 Request 则是被添加到 RequestManager 来进行管理。


对于上面的内容,主要就是说明通过 ActivityFragmentLifecycle,将 SupportRequestManagerFragmentRequestManager 建立了联系。

然后回到 SupportRequestManagerFragment 自身的实现,看到其生命周期方法:

// SupportRequestManagerFragment.javapublic void onStart() {
super.onStart(); lifecycle.onStart();}public void onStop() {
super.onStop(); lifecycle.onStop();}public void onDestroy() {
super.onDestroy(); lifecycle.onDestroy(); unregisterFragmentWithRoot();}

可以看到,不同的生命周期方法又会调用 lifecycle 对应的方法,而 lifecycle 就是前面说的 ActivityFragmentLifecycle

public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());}public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;}

而对于 ActivityFragmentLifecycle 有:

void onStart() {
isStarted = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart(); }}void onStop() {
isStarted = false; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop(); }}void onDestroy() {
isDestroyed = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy(); }}

lifecycleListenersSet<LifecycleListener>,其包含的元素就是在前面提到的 RequestManager 的构造方法中添加的,包括 RequestManager 自身,以及 RequestManager#connectivityMonitor

然后会在 ActivityFragmentLifecycle 对应的方法中回调 lifecycleListeners 中元素的对应的方法。(其中 Util.getSnapshot() 的目的是为了一个副本,防止对 lifecycleListeners 造成修改)


然后就是看 RequestManager 以及 RequestManager#connectivityMonitor 对应的实现了。

(1)对于 RequestManager

// RequestManager.javapublic synchronized void onStart() {
resumeRequests(); targetTracker.onStart();}public synchronized void onStop() {
// 暂停管理的 requests // 对应的暂停的逻辑大致就是释放与 requst 相关的资源,以及移除相关的回调 pauseRequests(); targetTracker.onStop();} public synchronized void onDestroy() {
targetTracker.onDestroy(); for (Target
target : targetTracker.getAll()) {
clear(target); } targetTracker.clear(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); mainHandler.removeCallbacks(addSelfToLifecycle); glide.unregisterRequestManager(this);}public synchronized void resumeRequests() {
requestTracker.resumeRequests();}

targetTrackerTargetTracker,还记得在 Glide.with(activity).load("").into(view) 这一

流程中,在 into() 方法中就会调用 RequestManager#track() 来开启资源的加载。

// RequestManager.javasynchronized void track(@NonNull Target
target, @NonNull Request request) {
targetTracker.track(target); requestTracker.runRequest(request);}

在该方法中,就会把传递进来的 Target(如 DrawableImageViewTarget) 添加到 targetTracker 中,把传递进来的 Request 添加到 requestTracker 中并开启 Request

比如 RequestManager#onStart() 方法,会通过 requestTracker.resumeRequests() 恢复内部管理的未完成的或者失败的 Request

// RequestTracker.java/** * Starts any not yet completed or failed requests. */public void resumeRequests() {
isPaused = false; for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isRunning()) {
// 开启 request request.begin(); } } pendingRequests.clear();}

以及调用 targetTracker.onStart() 来回调 targetTracker 内部管理的 Targer 实例的 onStrat() 方法。

(2)对于 RequestManager#connectivityMonitor

首先需要知道 connectivityMonitor 是什么。前面有提到 RequestManager 的构造方法,其就是在里面被实例化的。

connectivityMonitor =        factory.build(            context.getApplicationContext(),            new RequestManagerConnectivityListener(requestTracker));

其中 factory 默认为 DefaultConnectivityMonitorFactory。因此:

// DefaultConnectivityMonitorFactory.javapublic ConnectivityMonitor build(    @NonNull Context context,    @NonNull ConnectivityMonitor.ConnectivityListener listener) {
int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION); boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED; if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d( TAG, hasPermission ? "ACCESS_NETWORK_STATE permission granted, registering connectivity monitor" : "ACCESS_NETWORK_STATE permission missing, cannot register connectivity monitor"); } return hasPermission ? new DefaultConnectivityMonitor(context, listener) : new NullConnectivityMonitor();}

如果有网络权限,则 RequestManager#connectivityMonitor 默认为 DefaultConnectivityMonitor

因此对于 DefaultConnectivityMonitor#onStart() 有:

// DefaultConnectivityMonitor.javapublic void onStart() {
register();}private void register() {
if (isRegistered) {
return; } // Initialize isConnected. isConnected = isConnected(context); try {
// See #1405 context.registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); isRegistered = true; } catch (SecurityException e) {
// See #1417, registering the receiver can throw SecurityException. if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to register", e); } }}public void onStop() {
unregister();}public void onDestroy() {
// Do nothing.}

可以看到,DefaultConnectivityMonitor 是用于监听网络连接变化的。准确的说,会监听 ConnectivityManager.CONNECTIVITY_ACTION 这一广播。当回调 DefaultConnectivityMonitor#onStart() 时,就会重新注册对于广播的监听。

onStop() 则相反。

补充:

而当网络连接发生变化时,接收到广播之后回调用 DefaultConnectivityMonitor#listener.onConnectivityChanged(),而 listener 即为 RequestManagerConnectivityListener

// RequestManagerConnectivityListener.javapublic void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
synchronized (RequestManager.this) {
requestTracker.restartRequests(); } }}

requestTracker 就是 RequestManagerConnectivityListener 在实例化的时候传递进去的 RequestManager#requestTracker

// RequestTracker.javapublic void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCleared()) {
request.clear(); if (!isPaused) {
request.begin(); } else {
// Ensure the request will be restarted in onResume. pendingRequests.add(request); } } }}

因此最终的目的就是在 SupportRequestManagerFragment 生命周期内,监听网络连接的变化,从而在网络连接正常的情况下能够重新开始 request


最后的总结,Glide 对于生命周期的管理,简单说就是监听业务层的 Activity 或者 Fragment,在对应的生命周期,实现对于资源加载请求(即 Request)的开启或者暂停。


参考文章

转载地址:http://frerj.baihongyu.com/

你可能感兴趣的文章
Omap138开发板下以uboot2012.04.01为例分析uboot执行(六)
查看>>
Omap138开发板下以uboot2012.04.01为例分析uboot执行(七)
查看>>
Omap138开发板下以uboot2012.04.01为例分析uboot执行(八)
查看>>
Java发送邮件 注册成功发送邮件
查看>>
Mybatis的简单使用(增删改查),解决数据库字段名和实体类映射属性名不一致的问题
查看>>
Mybatis配置log4j文件 分页查询(limit,rowBounds)
查看>>
Mysql利用注解进行开发
查看>>
Mybatis一对多查询,多对一查询
查看>>
Spring配置bean.xml文件的头目录模板
查看>>
代理模式之------动态代理
查看>>
Spring实现AOP的三种方式
查看>>
Mybatis-Spring简单的配置和使用,配置事务
查看>>
SpringMVC和Mybatis整合使用的配置文件
查看>>
将字符串 “k:1|k1:2|k2:3|k3:4” 转换成字典{“k”:1,”k1”:2,”k2”:3,”k3”:4}
查看>>
AttributeError: 'tuple' object has no attribute 'decode'
查看>>
node爬虫(牛刀小试)
查看>>
关于vue的seo优化
查看>>
字符串在html中的页面中的换行
查看>>
react父子组件间的通信和传值
查看>>
vue-cli3.0设置环境变量
查看>>