【笔记整理】Glide 4.9.0 关于监听生命周期

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

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

// RequestManagerRetriever.java
private 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.java

public 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.java
public 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.java
synchronized 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.java
public 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.java
public 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.java
public void onConnectivityChanged(boolean isConnected) {
  if (isConnected) {
    synchronized (RequestManager.this) {
      requestTracker.restartRequests();
    }
  }
}

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

// RequestTracker.java
public 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)的开启或者暂停。


参考文章如何绑定页面生命周期(一)-Glide实现

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值