美文网首页Manba陪你学Android安卓开发博客Android源码分析
Android 【手撕Glide】--Glide是如何关联生命周

Android 【手撕Glide】--Glide是如何关联生命周

作者: 唠嗑008 | 来源:发表于2020-01-06 14:22 被阅读0次

    熟悉Glide的同学都知道,Glide加载图片是和Activity/Fragment生命周期相关联的,具体来说在onStart()去发起请求或者重新请求、 onStop()去暂停正在进行的请求、 onDestory()去取消清除请求。这样的好处是节约资源、避免内存泄漏。本文源码解析基于Glide 4.6.1

    系列文章
    Android 【手撕Glide】--Glide缓存机制
    Android 【手撕Glide】--Glide缓存机制(面试)
    Android 【手撕Glide】--Glide是如何关联生命周期的?

    学习指引

    下面通过2部分来讲解生命周期相关知识

    • 1、以Glide.with(activity)为例讲解Glide是如何关联生命周期的;
    • 2、在1中为了降低理解Glide生命周期的难度,去掉了部分分支和细节,这一部分在2中补充。

    时间紧张的朋友可以只看1就足以学会Glide生命周期原理了;时间充裕的朋友,建议你看看2中更详细的补充,这可以帮你更好的理解这个框架在设计上的优美。

    一、 关联生命周期的核心类

    • Glide:供外部调用的核心类,外观模式;
    • RequestManagerRetriever:是关联RequestManager和SupportRequestManagerFragment/RequestManagerFragment的中间类;
    • RequestManager:是用来加载、管理图片请求的,会结合Activity/Fragment生命周期对请求进行管理;
    • SupportRequestManagerFragment/RequestManagerFragment:Glide内部创建无UI的fragment,会与当前Activity绑定,与RequestManager绑定,传递页面的生命周期。其中SupportRequestManagerFragment是v4包下的Fragment,RequestManagerFragment:Glide是android.app.Fragment;
    • ActivityFragmentLifecycle:保存fragment和Requestmanager映射关系的类,管理LifecycleListener;
    • LifecycleListener:定义生命周期管理方法的接口,onStart(), onStop(), onDestroy()。

    二、关联生命周期的核心流程

    这部分主要讲RequestManager加载/管理请求的时候是如何感知当前Activity/Fragment生命周期的。

    Glide加载图片最基本的方式

    Glide.with(context).load("xxx")into(imageView);
    

    with()方法
    这个方法有多个重载,可以传入Context、Activity、Fragment、View等,但是内部调用方法都是一样的,只是参数有所不同,这里以传入FragmentActivity为例。

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

    这里先获取类RequestManagerRetriever对象,然后调用了它的get()方法。

    RequestManagerRetriever#get()

    @NonNull
      public RequestManager get(@NonNull FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
          return get(activity.getApplicationContext());
        } else {
          assertNotDestroyed(activity);
          //获取当前Activity的FragmentManager
          //用于后续将创建的Fragment绑定到activity
          FragmentManager fm = activity.getSupportFragmentManager();
          return supportFragmentGet(activity, fm, null /*parentHint*/);
        }
      }
    

    这里先判断是否在子线程,这个分支先不讲,先看看在主线程中的逻辑:先获取当前Activity的FragmentManager,,然后调用supportFragmentGet()

    RequestManagerRetriever#supportFragmentGet()

    @NonNull
      private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
          @Nullable Fragment parentHint) {
        //创建无UI的Fragment,并绑定到当前activity
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context);
          //创建RequestManager,获取fragment的lifecycle,传入requestManager
          requestManager =
              factory.build(
                  glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    

    RequestManagerRetriever#getSupportRequestManagerFragment()

    @NonNull
      SupportRequestManagerFragment getSupportRequestManagerFragment(
          @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
        //1、由FragmentManager通过tag获取fragment
        SupportRequestManagerFragment current =
            (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
          //2、从缓存集合中获取fragment的,map以fragmentManger为key,
          //以fragment为value进行存储
          current = pendingSupportRequestManagerFragments.get(fm);
          if (current == null) {
            //3、创建一个fragment实例
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
          }
        }
        return current;
      }
    

    1、创建无UI的Fragment,并绑定到当前activity;
    2、通过builder模式创建RequestManager,并且将fragment的lifecycle传入,这样Fragment和RequestManager就建立了联系;
    3、获取Fragment对象,先根据tag去找,如果没有从内存中查找,pendingSupportRequestManagerFragments是一个存储fragment实例的HashMap,再没有的话就new一个。

    SupportRequestManagerFragment的核心方法

    public class SupportRequestManagerFragment extends Fragment {
      private static final String TAG = "SupportRMFragment";
      private final ActivityFragmentLifecycle lifecycle;
    
        ...
    
      public SupportRequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
      }
    
      @VisibleForTesting
      @SuppressLint("ValidFragment")
      public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
      }
    
      @NonNull
      ActivityFragmentLifecycle getGlideLifecycle() {
        return 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();
      }
    }
    

    ActivityFragmentLifecycle# onStart()

    void onStart() {
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onStart();
        }
      }
    

    1、在创建Fragment的时候会创建ActivityFragmentLifecycle对象;
    2、在Fragment生命周期的方法中会调用Lifecycle的相关方法来通知RequestManager;
    3、LifecycleListener 是一个接口,Lifecycle最终是调用了lifecycleListener来通知相关的实现类的,也就是RequestManager。

    RequestManager类的关键部分

    public class RequestManager implements LifecycleListener {
    /**
       * Lifecycle callback that registers for connectivity events (if the
       * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
       * requests.
       */
      @Override
      public void onStart() {
        resumeRequests();
      }
    
      /**
       * Lifecycle callback that unregisters for connectivity events (if the
       * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
       */
      @Override
      public void onStop() {
        pauseRequests();
      }
    
      /**
       * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
       * all completed requests.
       */
      @Override
      public void onDestroy() {
        ...
        requestTracker.clearRequests();
      }
    }
    

    小结
    1、创建一个无UI的Fragment,具体来说是SupportRequestManagerFragment/RequestManagerFragment,并绑定到当前Activity,这样Fragment就可以感知Activity的生命周期;
    2、在创建Fragment时,初始化LifecycleLifecycleListener,并且在生命周期的onStart() 、onStop()、 onDestroy()中调用相关方法;
    3、在创建RequestManager时传入Lifecycle 对象,并且LifecycleListener实现了LifecycleListener接口;
    4、这样当生命周期变化的时候,就能通过接口回调去通知RequestManager处理请求。

    三、关联生命周期相关补充

    还记得在介绍RequestManagerRetriever#get()方法获取RequestManager对象时我们传入的参数是FragmentActivity吗?实际上这个方法有多个重载:

    RequestManager get(@NonNull Context context) {}
    RequestManager get(@NonNull FragmentActivity activity) {}
    RequestManager get(@NonNull Fragment fragment) {}
    RequestManager get(@NonNull Activity activity) {}
    RequestManager get(@NonNull View view) {}
    

    虽然有多个重载,但是总体上只有2种情况,即传入的是否为Application类型参数。

      @NonNull
      public RequestManager get(@NonNull Context context) {
        if (context == null) {
          throw new IllegalArgumentException("You cannot start a load on a null Context");
        } else if (Util.isOnMainThread() && !(context instanceof Application)) {
          if (context instanceof FragmentActivity) {
            return get((FragmentActivity) context);
          } else if (context instanceof Activity) {
            return get((Activity) context);
          } else if (context instanceof ContextWrapper) {
            return get(((ContextWrapper) context).getBaseContext());
          }
        }
        //子线程或者传入Application Context
        return getApplicationManager(context);
      }
    

    1、传入Application Context或者在子线程使用:调用getApplicationManager(context);这样Glide的生命周期就和应用程序一样了。

    @NonNull
      private RequestManager getApplicationManager(@NonNull Context context) {
        // Either an application context or we're on a background thread.
        if (applicationManager == null) {
          synchronized (this) {
            if (applicationManager == null) {
              // Normally pause/resume is taken care of by the fragment we add to the fragment or
              // activity. However, in this case since the manager attached to the application will not
              // receive lifecycle events, we must force the manager to start resumed using
              // ApplicationLifecycle.
    
              // TODO(b/27524013): Factor out this Glide.get() call.
              Glide glide = Glide.get(context.getApplicationContext());
              applicationManager =
                  factory.build(
                      glide,
                      new ApplicationLifecycle(),
                      new EmptyRequestManagerTreeNode(),
                      context.getApplicationContext());
            }
          }
        }
    
        return applicationManager;
      }
    

    这里获取RequestManager对象的方式和之前传入Activity、Fragment对象是有所区别的,之前是创建了一个SupportRequestManagerFragment/RequestManagerFragment对象,然后获取其内部创建的Lifecycle对象作为参数传到RequestManager;而这里的主要差异是获取Lifecycle对象不一样,用的是ApplicationLifecycle,由于没有创建Fragment,这里只会调用onStart(),这种情况Glide生命周期就和Application一样长了。

    class ApplicationLifecycle implements Lifecycle {
      @Override
      public void addListener(@NonNull LifecycleListener listener) {
        listener.onStart();
      }
    
      @Override
      public void removeListener(@NonNull LifecycleListener listener) {
        // Do nothing.
      }
    }
    

    2、其它情况,比如传入Activity、Fragment等:最后只会调用fragmentGet() 、或者supportFragmentGet()中的一个,这样Glide就可以关联生命周期,会在生命周期不同的方法中对请求做不同的处理。

    @NonNull
      private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
          @Nullable Fragment parentHint) {
        //创建无UI的Fragment,并绑定到当前activity
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context);
          //创建RequestManager,获取fragment的lifecycle,传入requestManager
          requestManager =
              factory.build(
                  glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          //fragment与RequestManager关联
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    
    @NonNull
      private RequestManager fragmentGet(@NonNull Context context,
          @NonNull android.app.FragmentManager fm,
          @Nullable android.app.Fragment parentHint) {
        RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
        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;
      }
    

    2个方法等实现其实都是一样的,唯一的区别是supportFragmentGet创建的是v4包下的Fragment,fragmentGet创建的是android.app.Fragment

    RequestManagerRetriever#getSupportRequestManagerFragment()

    @NonNull
      SupportRequestManagerFragment getSupportRequestManagerFragment(
          @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
        //1、由FragmentManager通过tag获取fragment
        SupportRequestManagerFragment current =
            (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
          //2、从缓存集合中获取fragment的,map以fragmentManger为key,
          //以fragment为value进行存储
          current = pendingSupportRequestManagerFragments.get(fm);
          if (current == null) {
            //3、创建一个fragment实例
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            //将创建的Fragment放入HashMap缓存
            pendingSupportRequestManagerFragments.put(fm, current);
            //提交事物,将fragment绑定到Activity       
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
       //发消息,从map缓存中删除fragment        
       handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
          }
        }
        return current;
      }
    
    @Override
      public boolean handleMessage(Message message) {
       ...
        switch (message.what) {
          case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
            FragmentManager supportFm = (FragmentManager) message.obj;
            key = supportFm;
            //从map缓存中删除fragment        
            removed = pendingSupportRequestManagerFragments.remove(supportFm);
            break;
      }
    

    看一下这里获取Fragment的流程,首先由FragmentManager通过tag获取;如果没有就从pendingSupportRequestManagerFragments这个Map从获取;再没有的话就new一个SupportRequestManagerFragment对象,并且把fragment对象放入map缓存起来,接着通过FragmentManager将fragment与activity绑定,但是紧接着又调用handle发送了一条消息。

    这里有个问题很奇怪,刚把创建的fragment对象放入map缓存起来,但是马上又通过handler把它删除,这是什么情况?

    原因是这样的,当调用FragmentManageradd()方法时,是通过开启事务的方式来进行绑定的,这个过程是异步的,具体来说,就是调用add方法时,并不是马上就和activity绑定好了,而是通过Hander来处理的。

    下面来看一种应用场景

    @Override
        protected void onStart() {
            super.onStart();
            Glide.with(this).load("xx").into(image1);
            Glide.with(this).load("xx").into(image2);
        }
    

    1、在第一次调用第一行代码的时候,会生成一个Fragment对象,通过FragmentManager出发Fragment于Activity绑定,这个绑定过程是通过Handler发消息来完成的,假设这个消息为m1;
    2、紧接着使用Handler来发送消息从HashMap中删除刚才保存的Fragment,假设这个消息为m2;
    3、由于是异步的,在消息未处理之前已经开始执行第二行Glide代码了,具体说可能是m1,m2还没有处理,就已经开始调用getSupportRequestManagerFragment方法了,这个方法内部是获取Fragment对象的,具体分析上面说过了;如果不用map来缓存fragment,那么代码流程应该是这样的

    不使用map获取fragment

    此时通过findFragmentByTag还没有找到Fragment,就会重新生成一个Fragment,这是Glide所不允许的,每一个Activity或者Fragment在使用Glide时,只能有一个所依附的虚拟的Fragment。所以将之前所生成的Fragment存储到HashMap中,这样就不会重复生成。等到SupportRequestManagerFragment与Activity绑定完成后,也就是消息m1处理完成后,再将Fragment从Map中销毁。

    总结

    1、在使用Glide的时候尽量传入Activity或者Fragment的,这样才能绑定/关联生命周期;使用ApplicationContext的话会使得Glide生命周期和Application一样长;
    2、在UI线程中调用Glide,在子线程使用的话会和使用ApplicationContext一样;
    3、Glide关联生命周期主要分为2个部分:如何感应当前页面的生命周期?通过创建一个无UI的Fragment来实现;如何传递生命周期?RequestManager与Fragment之间通过Lifecycle、LifecycleListener接口回调的方式来实现。更详细的可以看第二部分的小结。
    4、一个疑问:为什么Glide不通过Google的Lifecycle来实现RequestManager关联生命周期呢?这个库自sdk26就继承到Android源码的Activity/Fragment中了。

    参考:
    https://www.jianshu.com/p/b7d895b9f32c
    https://www.jianshu.com/p/4ab09771aed1
    https://www.jianshu.com/p/bb08d5fb97ae

    相关文章

      网友评论

        本文标题:Android 【手撕Glide】--Glide是如何关联生命周

        本文链接:https://www.haomeiwen.com/subject/smbqactx.html