Glide生命周期原理

本文首发于 vivo互联网技术 微信公众号 
链接:https://mp.weixin.qq.com/s/uTv44vJFFJI_l6b5YKSXYQ
作者:连凌能

Android App中图片的展示是很基本也很重要的一个功能,在Android平台上有很多的图片加载解决方案,但是官方认可的是Glide。Android App的页面是有生命周期的,Glide比较好的一个功能就是具有生命周期管理功能,能够根据页面和APP的生命周期来管理图片的加载和停止,也开放接口供用户在内存紧张时手动进行内存管理。本文重点是生命周期源码的分析,不会从简单的使用着手。

一、综述

这是Glide源码分析的第二篇文章,第一篇是《Glide缓存流程》,从资源的获取流程对源码进行分析。本篇会聚焦于生命周期模块的原理。开始之前先思考下面这几个问题:

  • Glide怎么实现页面生命周期?

  • Glide为什么对Fragment做缓存?

  • Glide如何监听网络变化?

  • Glide如何监测内存?

 

二、Glide生命周期传递

先来看with函数的执行, 会构造glide单例,而 

RequestManagerRetriever在initializeGlide中会进行构造。


// Glide.java
public static RequestManager with(@NonNull Activity activity) {
   return getRetriever(activity).get(activity); } @NonNull 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(); } @NonNull public static Glide get(@NonNull Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; } private static void checkAndInitializeGlide(@NonNull Context context) { // In the thread running initGlide(), one or more classes may call Glide.get(context). // Without this check, those calls could trigger infinite recursion. if (isInitializing) { throw new IllegalStateException("You cannot call Glide.get() in registerComponents()," + " use the provided Glide instance instead"); } isInitializing = true; initializeGlide(context); isInitializing = false; }

构造完成RequestManagerRetriever通过get返回一个 RequestManager, 如果不在主线程,默认会传入 getApplicationContext,也就是不进行生命周期管理:

  • 在getRequestManagerFragment中先查看当前Activity中有没有FRAGMENT_TAG这个标签对应的Fragment,如果有就直接返回

  • 如果没有,会判断pendingRequestManagerFragments中有没有,如果有就返回

  • 如果没有,就会重写new一个,然后放入到pendingRequestManagerFragments中,然后添加到当前Activity,再给Handler发送一条移除的消息


// RequestManagerRetriever.java
 @NonNull
 public RequestManager get(@NonNull Activity activity) {
   if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet( activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = getRequestManagerFragment(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 = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; } private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); if (isParentVisible) { current.getGlideLifecycle().onStart(); } pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; } public boolean handleMessage(Message message) { ... switch (message.what) { case ID_REMOVE_FRAGMENT_MANAGER: android.app.FragmentManager fm = (android.app.FragmentManager) message.obj; key = fm; removed = pendingRequestManagerFragments.remove(fm); break; ... } ... }

这里面需要注意一个问题,就是如果with()函数中传进来的不是Activity,而是Fragment,那么也会去创建一个没有界面的RequestManagerFragment,而它的父Fragment就是传进来的Fragment。

上面为什么需要pendingRequestManagerFragments先进行缓存呢?这个放到下面第二个问题中说明。先接着往下看生命周期的传递。

RequestManagerFragment是一个很重要的类,Glide就是通过它作为生命周期的分发入口,RequestManagerFragment的默认构造函数会实例化一个ActivityFragmentLifecycle,在每个生命周期onStart/onStop/onDestroy中会调用ActivityFragmentLifecycle:


// RequestManagerFragment.java
public class RequestManagerFragment extends Fragment { private static final String TAG = "RMFragment"; private final ActivityFragmentLifecycle lifecycle; @Nullable private RequestManager requestManager; public RequestManagerFragment() { this(new ActivityFragmentLifecycle()); } RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this.lifecycle = lifecycle; } @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(); } ... }

RequestManagerFragment里面有一个实例RequestManager,在前面的fragmentGet,RequestManagerFragment拿到以后会尝试获取它的RequestManager,第一次获取肯定是没有,就会重新构造一个, 通过RequestManagerRetriever构造时传入的RequestManagerFactory工厂类实例化一个RequestManager, 把RequestManagerFragment中的ActivityFragmentLifecycle传进去:


// RequestManagerRetriever.java
public interface RequestManagerFactory { @NonNull RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context); } private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() { @NonNull @Override public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); } };

很明显生命周期的关键就在ActivityFragmentLifecycle, 在RequestManagerFragment中相应生命周期中会回调它,那么猜测它肯定是在里面维护了一个观察者列表,相应事件发生的时候进行通知, 看下它的源码:


// ActivityFragmentLifecycle.java
class ActivityFragmentLifecycle implements Lifecycle {
  private final Set lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap());
  private boolean isStarted; private boolean isDestroyed; @Override public void addListener(@NonNull LifecycleListener listener) { lifecycleListeners.add(listener); 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(); } } }

所以RequestManagerFragment把这个传给RequestManager后,肯定会注册观察者,看一下RequestManager的相关代码,在构造函数里面lifecycle.addListener(this);,把自己注册为观察者:


// RequestManager.java
public class RequestManager implements LifecycleListener,
    ModelTypes> {
  ...
  protected final Glide glide;
  protected final Context context;
  @Synthetic final Lifecycle lifecycle;
  private final RequestTracker requestTracker;
  private final RequestManagerTreeNode treeNode;
  private final TargetTracker targetTracker = new TargetTracker();
  private final Runnable addSelfToLifecycle = new Runnable() {
    @Override
    public void run() {
      lifecycle.addListener(RequestManager.this);
    }
  };
  private final Handler mainHandler = new Handler(Looper.getMainLooper());
  private final ConnectivityMonitor connectivityMonitor;
 
  private RequestOptions requestOptions;
 
  public RequestManager(
      @NonNull Glide glide, @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
    this(
        glide,
        lifecycle,
        treeNode,
        new RequestTracker(),
        glide.getConnectivityMonitorFactory(),
        context);
  }
 
  // Our usage is safe here.
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;
 
    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));
 
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);
 
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
 
    glide.registerRequestManager(this);
  }

在看下RequestManager对应的生命周期里面, 在这里面分别启动,停止和销毁请求:

// RequestManager
@Override
  public void onStart() { resumeRequests(); targetTracker.onStart(); } @Override public void onStop() { pauseRequests(); targetTracker.onStop(); } @Override public 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); }

三、Glide为什么对Fragment做缓存?

再贴一次RequestManagerRetriever中获取Fragment的代码,前面留了一个疑问,为什么这里会需要一个pendingRequestManagerFragments对Fragment进行缓存。

// RequestManagerRetriever.java
  /**
   * Pending adds for RequestManagerFragments.
   */
  @SuppressWarnings("deprecation")
  @VisibleForTesting final Map pendingRequestManagerFragments = new HashMap<>(); private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); if (isParentVisible) { current.getGlideLifecycle().onStart(); } pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }

我们看一个情况:

Glide.with(Context).load(ImageUrl1).into(imageview1); // task1
Glide.with(Context).load(ImageUrl2).into(imageview2); // task2

Android开发应该都知道主线程有一个Handler机制,会往消息队列中放消息,通过Looper按顺序取出来执行。那么主线程中的执行顺序和消息队列中的执行顺序关系是什么?看个栗子:


private void start() {
     mHandler = new Handler(getMainLooper());
 
     VLog.i("HandlerRunT", "=========Begin!============"); mHandler.post(new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========First!============"); } }); VLog.i("HandlerRunT", "=========Middle!============"); mHandler.sendMessage(Message.obtain(mHandler, new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Second!============"); } })); VLog.i("HandlerRunT", "=========End!============"); Next(); } private void Next() { VLog.i("HandlerRunT", "=========Next Begin!============"); mHandler.post(new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Next First!============"); } }); VLog.i("HandlerRunT", "=========Next Middle!============"); mHandler.sendMessage(Message.obtain(mHandler, new Runnable() { @Override public void run() { VLog.i("HandlerRunT", "=========Next Second!============"); } })); VLog.i("HandlerRunT", "=========Next End!============"); }

在start中打印的顺序和它里面的Handler中的信息哪个先打印?start中handler的信息和Next函数中的信息打印顺序是怎样的?看下打印结果:

HandlerRunT: =========Begin!============
HandlerRunT: =========Middle!============
HandlerRunT: =========End!============
HandlerRunT: =========Next Begin!============
HandlerRunT: =========Next Middle!============
HandlerRunT: =========Next End!============
HandlerRunT: =========First!============
HandlerRunT: =========Second!============
HandlerRunT: =========Next First!============
HandlerRunT: =========Next Second!============

Handler中的顺序会在主线程之后,Handler中的消息执行顺序就是队列先进先出。

上面执行到task1的时候,在下面这两行代码,add操作会往消息队列放一个消息,这里标记为msg1:

fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();

 

// FragmentManager.java
    public void enqueueAction(OpGenerator action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || mHost == null) { if (allowStateLoss) { // This FragmentManager isn't attached, so drop the entire transaction. return; } throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<>(); } mPendingActions.add(action); scheduleCommit(); } } private void scheduleCommit() { synchronized (this) { boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1; if (postponeReady || pendingReady) { mHost.getHandler().removeCallbacks(mExecCommit); mHost.getHandler().post(mExecCommit); } } }

那么如果不把task1中构造的RequestManagerFragment放到pendingRequestManagerFragments中,那么在执行task2的时候也会再重新构造一个RequestManagerFragment,并且往主线程中放一个消息msg2,这个时候就会出现重复add的情况。

所以在前面new 出来一个RequestManagerFragment,随后就把它放到pendingRequestManagerFragments中,那么task2再进来的时候从缓存中能取到,就不会再重新new和add了。

那么下一个问题来了,为什么会出现下面这行代码,add后又需要马上发一个消息remove掉?在前面阻止掉task2重复new和add的操作后,就把这个缓存删掉,可以避免内存泄漏和内存压力:

// RequestManagerRetriever.java
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();

四、Glide如何监听网络变化

从上面页面生命周期的分析部分知道,对于任务的控制都是通过RequestManager,还是到它里面去看,实现网络变化监听的就是ConnectivityMonitor:

// RequestManager.java
public class RequestManager implements LifecycleListener,
    ModelTypes> {
  ...
  protected final Glide glide;
  protected final Context context;
  @Synthetic final Lifecycle lifecycle;
  private final RequestTracker requestTracker;
  private final RequestManagerTreeNode treeNode;
  private final TargetTracker targetTracker = new TargetTracker();
  private final Handler mainHandler = new Handler(Looper.getMainLooper());
  private final ConnectivityMonitor connectivityMonitor;
 
  ...
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;
 
    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));
 
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);
    ...
  }

所以也是把它注册为ActivityFragmentLifecycle的观察者,ConnectivityMonitor通过ConnectivityMonitorFactory进行构造,提供了默认实现类DefaultConnectivityMonitorFactory:

// DefaultConnectivityMonitorFactory.java
public class DefaultConnectivityMonitorFactory implements ConnectivityMonitorFactory { private static final String TAG = "ConnectivityMonitor"; private static final String NETWORK_PERMISSION = "android.permission.ACCESS_NETWORK_STATE"; @NonNull @Override public ConnectivityMonitor build( @NonNull Context context, @NonNull ConnectivityMonitor.ConnectivityListener listener) { int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION); boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED; return hasPermission ? new DefaultConnectivityMonitor(context, listener) : new NullConnectivityMonitor(); } }

接着就往下看DefaultConnectivityMonitor, 在onStart中registerReceiver监听手机网络状态变化的广播,然后在connectivityReceiver中调用isConnect进行网络状态确认,根据网络状态是否变化,如果有变化就回调监听ConnectivityMonitor.ConnectivityListener:


final class DefaultConnectivityMonitor implements ConnectivityMonitor {
  private static final String TAG = "ConnectivityMonitor"; private final Context context; @SuppressWarnings("WeakerAccess") @Synthetic final ConnectivityListener listener; @SuppressWarnings("WeakerAccess") @Synthetic boolean isConnected; private boolean isRegistered; private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() { @Override public void onReceive(@NonNull Context context, Intent intent) { boolean wasConnected = isConnected; isConnected = isConnected(context); if (wasConnected != isConnected) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "connectivity changed, isConnected: " + isConnected); } listener.onConnectivityChanged(isConnected); } } }; DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) { this.context = context.getApplicationContext(); this.listener = listener; } 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); } } } private void unregister() { if (!isRegistered) { return; } context.unregisterReceiver(connectivityReceiver); isRegistered = false; } @SuppressWarnings("WeakerAccess") @Synthetic // Permissions are checked in the factory instead. @SuppressLint("MissingPermission") boolean isConnected(@NonNull Context context) { ConnectivityManager connectivityManager = Preconditions.checkNotNull( (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); NetworkInfo networkInfo; try { networkInfo = connectivityManager.getActiveNetworkInfo(); } catch (RuntimeException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e); } // Default to true; return true; } return networkInfo != null && networkInfo.isConnected(); } @Override public void onStart() { register(); } @Override public void onStop() { unregister(); } @Override public void onDestroy() { // Do nothing. } }

ConnectivityMonitor.ConnectivityListener是在RequestManager中传入,有网络重新连接后重启请求:

// RequestManager.java
  private static class RequestManagerConnectivityListener implements ConnectivityMonitor .ConnectivityListener { private final RequestTracker requestTracker; RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) { this.requestTracker = requestTracker; } @Override public void onConnectivityChanged(boolean isConnected) { if (isConnected) { requestTracker.restartRequests(); } } }

五、Glide如何监测内存

在Glide构造的时候会调用registerComponentCallbacks进行全局注册, 系统在内存紧张的时候回调onTrimMemory,然后根据系统内存紧张级别进行memoryCache/bitmapPool/arrayPool的回收:

// Glide.java
  public static Glide get(@NonNull Context context) {
    if (glide == null) { synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context); } } } return glide; } private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) { Context applicationContext = context.getApplicationContext(); ... applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; } @Override public void onTrimMemory(int level) { trimMemory(level); } public void trimMemory(int level) { Util.assertMainThread(); memoryCache.trimMemory(level); bitmapPool.trimMemory(level); arrayPool.trimMemory(level); }

六、总结

再回顾前面的四个问题,我相信聪明的你已经有了答案,文章的各小节标题就是根据问题来进行分析的,这么就不再赘述了,要不有凑字数的嫌疑。Glide的源码是比较庞大而且高质量的,所以一两篇文章是说不清楚的,后面对于Glide的源码分析还会有后续的文章,欢迎关注。

 

更多内容敬请关注 vivo 互联网技术 微信公众号

Glide生命周期原理_第1张图片

注:转载文章请先与微信号:labs2020 联系。

你可能感兴趣的:(Glide生命周期原理)