Glide生命周期管理

March 1, 2019

前言

图片加载时只需调用以下代码,Glide 会自动完成下载、缓存、缩放、展示等流程。

1
2
3
Glide.with(this)
        .load("http://www.abc.com")
        .into(imageView)

其中包含应用进入后台,图片会暂停加载的策略。通过这篇文章,探究 Glide 是如何实现开发者不主动触发逻辑,就能实现任务生命周期自动管理的奥秘。Glide 4.9.0

Glide

上面的Glide.with(this)根据传入实参类型,例如:FragmentActivityFragmentContext 等不同选择目标重载方法。

这里通过 FragmentActivity 进行解析,常用 AppCompatActivity 的父类是 FragmentActivity,便于理解。

1
2
3
public static RequestManager with(@NonNull FragmentActivity activity) {
  return getRetriever(activity).get(activity);
}

检查参数提供的 Context 是否为空:当 Fragment 与页面绑定前或解除绑定后,这些生命周期内获得宿主 Activity 为空。获取 Glide 单例并提取里面的 RequestManagerRetriever 实例。

1
2
3
4
5
6
7
8
9
10
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  // Context could be null for other reasons (ie the user passes in null), but in practice it will
  // only occur due to errors with the Fragment lifecycle.
  Preconditions.checkNotNull(
      context,
      "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
          + "returns null (which usually occurs when getActivity() is called before the Fragment "
          + "is attached or after the Fragment is destroyed).");
  return Glide.get(context).getRequestManagerRetriever();
}

RequestManagerRetriever

忽略 Glide 首次初始化流程,来到 RequestManagerRetriever 获取 RequestManager 实例的流程。

1
2
3
4
5
6
7
8
9
10
11
12
public RequestManager get(@NonNull FragmentActivity activity) {
  // 线程判断:Looper.myLooper() != Looper.getMainLooper()
  if (Util.isOnBackgroundThread()) {
    // 页面在后台线程时获取ApplicationContext
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    // 从Activity实例获取FragmentManager
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(activity, fm, null, isActivityVisible(activity));
  }
}

从上面可见条件判断根据应用是否在主线程走分支,而本文仅关心应用在主线程的逻辑。进入分支后可见从 Activity 实例获取 FragmentManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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) {
    Glide glide = Glide.get(context);
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

以下方法从 ActivityFragmentManager 中查找是否存在名为 FRAGMENT_TAGFragment 实例。这个实例相当于一个隐形的钩子,挂在 Activity 监听界面生命周期变化,并回调 Glide 图片加载策略。

1
static final String FRAGMENT_TAG = "com.bumptech.glide.manager";

实例不存在就创建 Fragment 实例,这个实例类型为 SupportRequestManagerFragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private SupportRequestManagerFragment getSupportRequestManagerFragment(
    @NonNull final FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {

  // 首先用FRAGMENT_TAG字符串的方式从fm里面找Fragment
  SupportRequestManagerFragment current =
      (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  
  // 字符串的方式找不到
  if (current == null) {
    // 每个FragmentActivity只有一个FragmentManager;
    // 每个FragmentManager只存一个SupportRequestManagerFragment;
    // 所以试着用FragmentManager获取SupportRequestManagerFragment实例
    current = pendingSupportRequestManagerFragments.get(fm);
    // 判断实例为空则需构建Fragment实例并加入到Activity
    if (current == null) {
      // 创建新实例
      current = new SupportRequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      // Activity可见,触发Fragment的onStart()逻辑调用
      if (isParentVisible) {
        current.getGlideLifecycle().onStart();
      }
      pendingSupportRequestManagerFragments.put(fm, current);
      // 把SupportRequestManagerFragment加入到Activity的FragmentManager中
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

所有创建的 SupportRequestManagerFragment 都保存在以下哈希表中,即自行保存一份关系列表

1
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments = new HashMap<>();

SupportRequestManagerFragment

接下来看看上面提及的 SupportRequestManagerFragment

从签名可知此类继承父类为 Fragment。但不像一般 Fragment 包含UI界面,这个实例仅包含生命周期的相关回调操作。说白了,就是借用 Fragment 当钩子达到监听 Activity 生命周期的目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class SupportRequestManagerFragment extends Fragment {
  // 生命周期回调
  private final ActivityFragmentLifecycle lifecycle;
  private final RequestManagerTreeNode requestManagerTreeNode =
      new SupportFragmentRequestManagerTreeNode();
  private final Set<SupportRequestManagerFragment> childRequestManagerFragments = new HashSet<>();

  @Nullable private SupportRequestManagerFragment rootRequestManagerFragment;
  @Nullable private RequestManager requestManager;
  @Nullable private Fragment parentFragmentHint;

  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
    
  .....

  @Override
  public void onAttach(Context context) {
    super.onAttach(context);
    try {
      registerFragmentWithRoot(getActivity());
    } catch (IllegalStateException e) {
      // OnAttach can be called after the activity is destroyed, see #497.
    }
  }
    
  // 注意下面不同生命周期对lifecycle的调用

  @Override
  public void onDetach() {
    super.onDetach();
    parentFragmentHint = null;
    unregisterFragmentWithRoot();
  }

  @Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }
}

ActivityFragmentLifecycle

最后进入 ActivityFragmentLifecycle 实现类,这个类其实就是观察者模式的具体实现。所有需要加载图片的任务,会创建 LifecycleListener 监听器放入 ActivityFragmentLifecycle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class ActivityFragmentLifecycle implements Lifecycle {
  // 监听器集合
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());

  private boolean isStarted;
  private boolean isDestroyed;

  // 把给定的监听器添加到监听器列表,以便接收生命周期事件的通知
  // 最新的生命周期事件会在所有注册的监听器上触发
  // 若activity或fragment被stop,会调用LifecycleListener.onStop()
  // onStart和onDestroy生命周期有类似操作
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

    // 把最新界面状态通知给新来的LifecycleListener
    if (isDestroyed) {
      listener.onDestroy();
    } else if (isStarted) {
      listener.onStart();
    } else {
      listener.onStop();
    }
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

  // 下发生命周期通知,观察者模式
  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();
    }
  }
}

最后,定制的 Fragment 监听 Activity 生命周期变化,告知 ActivityFragmentLifecycle ,随后 ActivityFragmentLifecycle 回调所有注册的监听器,实现应用进入后台暂停加载等功能。

下面就是 ActivityFragmentLifecycle 回调的逻辑类,负责请求的跟踪、取消、重启、完成和失败的管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
public class RequestTracker {
  private static final String TAG = "RequestTracker";
  // Most requests will be for views and will therefore be held strongly (and safely) by the view
  // via the tag. However, a user can always pass in a different type of target which may end up not
  // being strongly referenced even though the user still would like the request to finish. Weak
  // references are therefore only really functional in this context for view targets. Despite the
  // side affects, WeakReferences are still essentially required. A user can always make repeated
  // requests into targets other than views, or use an activity manager in a fragment pager where
  // holding strong references would steadily leak bitmaps and/or views.
  private final Set<Request> requests =
      Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
  // 保存未完成或准备运行请求的列表,用于持有这些请求的强引用
  // 以保证请求在开始执行之前或暂停的时候不会被垃圾回收
  @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
  private final List<Request> pendingRequests = new ArrayList<>();
  private boolean isPaused;

  // 开始跟踪指定请求
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

  @VisibleForTesting
  void addRequest(Request request) {
    requests.add(request);
  }

  // 停止跟踪指定请求,并进行清除和回收工作
  // 请求已被移除、失效返回true;请求找不到时返回false
  public boolean clearRemoveAndRecycle(@Nullable Request request) {
    // 此时回收请求是安全的,因为这个操作由用户主动清除时触发,因此可知没有其他持有请求的引用
    return clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ true);
  }

  private boolean clearRemoveAndMaybeRecycle(@Nullable Request request, boolean isSafeToRecycle) {
     if (request == null) {
      // 请求为空表示请求已被清除,不再需要查找请求的所有者
      return true;
    }
    boolean isOwnedByUs = requests.remove(request);
    // Avoid short circuiting.
    isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
    if (isOwnedByUs) {
      request.clear();
      if (isSafeToRecycle) {
        request.recycle();
      }
    }
    return isOwnedByUs;
  }

  // 暂停所有正在进行的请求
  public void pauseRequests() {
    isPaused = true;
    for (Request request : Util.getSnapshot(requests)) {
      if (request.isRunning()) {
        request.clear();
        pendingRequests.add(request);
      }
    }
  }

  // 暂停所有正在进行的请求,释放已完成任务的关联bitmaps
  public void pauseAllRequests() {
    isPaused = true;
    for (Request request : Util.getSnapshot(requests)) {
      if (request.isRunning() || request.isComplete()) {
        request.clear();
        pendingRequests.add(request);
      }
    }
  }

  // 重启所有未完成或曾经失败的任务
  public void resumeRequests() {
    isPaused = false;
    for (Request request : Util.getSnapshot(requests)) {
      // We don't need to check for cleared here. Any explicit clear by a user will remove the
      // Request from the tracker, so the only way we'd find a cleared request here is if we cleared
      // it. As a result it should be safe for us to resume cleared requests.
      if (!request.isComplete() && !request.isRunning()) {
        request.begin();
      }
    }
    pendingRequests.clear();
  }

  // 取消所有请求并清理任务持有的资源,取消的请求将不能再次重启
  public void clearRequests() {
    for (Request request : Util.getSnapshot(requests)) {
      // 在这里回收请求的不安全的,因为不知道别的地方是否持有请求的引用
      // 方法形参isSafeToRecycle赋值为false
      clearRemoveAndMaybeRecycle(request, false);
    }
    pendingRequests.clear();
  }

  // 从起失败的、取消的、正在进行的请求
  public void restartRequests() {
    for (Request request : Util.getSnapshot(requests)) {
      if (!request.isComplete() && !request.isCleared()) {
        request.clear();
        if (!isPaused) {
          request.begin();
        } else {
          // 确保请求在onResume生命周期正常重启
          pendingRequests.add(request);
        }
      }
    }
  }
}

总结

通过上述流程可知,Glide 的图片加载生命周期管理依赖传入的 Context 实例。如果实例类型为 ActivityGlide 就能注册一个没有界面的 FragmentActivity,达到监听生命周期变化的目的。

因此,该参数应尽可能传入 ActivityFragment 对象,最少也得是 View 持有的 Context,而不是 ApplicationContext。不然图片的生命周期会超过界面实际的生命周期。

Glide_lifecycle_hierarchy

最后,Glide 监听界面生命周期变化没有什么奥秘,就是把定制的 Fragment 添加到图片所在的 Activity 中,利用系统机制监听周期变化,在不同周期通知图片进行不同操作