Glide源码分析——Request管理

Glide作为一个优秀的图片加载框架,有很多值得我们学习的地方,这次我们来看看它是如何管理图片加载的请求吧;特别是它是如何感知Activity/Fragment的生命周期的方式。

文章目录


 在Glide中会把每个图片加载请求封装成一个Request对象,而这些Request对象的管理里是RequestManager。在了解Request Manager对Request管理之前,我们先来看下Glide请求显示过程,请求过程大致如下时序图所示:
Glide源码分析——Request管理
 时序图中省略了RequestManager对象创建、Request具体加载过程等细节;关于Request具体加载过程,我们以后的文章再讲解,我们这篇文章主要看下RequestManager对象创建、它是如何感知Activity/Fragment生命周期以及它对Request的管理。

RequestManager对象创建

 RequestManager,从名称也能看出它是管理Request的对象,事实上也确实如此。RequestManager对象创建是在RequestManagerRetriever.get()方法过程中实现的, RequestManagerRetriver有多个重载的get()方法,这跟调用Glide.with()时传入的参数有关。

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

虽重载方法有6个,但实际上创建RequestManager对象只有5种情况:

  • Activity
  • FragmentActivity
  • Fragment
  • android.app.Fragment
  • Application Context

除了ApplicationContext,其他几种情况都会创建一个SupportRequestManagerFragment(备注:Activity和android.app.Fragment情况会创建RequestManagerFragment,后面的分析都是基于SupportRequestManagerFragment,他们的原理是一致的)与创建的RequestManager对象关联;RequestManager对Request的管理会受SupportRequestManagerFragment生命周期的影响。接下来我们看下RequestManager对象创建过程,先看RequestManagerRetriever.get(FragmentActivity activity)方法

//RequestManagerRetriever.java
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  if (Util.isOnBackgroundThread()) {
    //如果是非UI线程,则调用get(Context context)方法,并传入Application Context
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    //注意这个地方,调用的是getSupportFragmentManager()方法;
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

Application Context实现

我们先看非UI线程下创建RequestManager对象,在此条件下会调用get(Context context)方法,并传入Application Context。在get(Context context)方法实现种,如果是非UI线程会调用getApplicationManager(Context context)方法,并返回RequestManager对象,我们直接看getApplicationManager(Context context)方法。

//RequestManagerRetriever.java
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
  //通过double-check的方式创建applicationManager对象
  if (applicationManager == null) {
    synchronized (this) {
      if (applicationManager == null) {
        Glide glide = Glide.get(context.getApplicationContext());
        applicationManager =
            //通过factory创建RequestManager对象
            factory.build(
                glide,
                new ApplicationLifecycle(),//注意这里创建的是ApplicationLifecycle()对象
                new EmptyRequestManagerTreeNode(),
                context.getApplicationContext());
      }
    }
  }

  return applicationManager;
}

applicationManager是RequestManagerRetriever对象变量,通过double-check的方式保证了applicationManager对象的唯一性。这里需要注意的一点是创建RequestManager的时候传入的Lifecycle参数是ApplicationLifecycle对象引用,至于为什么要注意,我们后面再讲。

FragmentActivity实现

 接下来,看下get(FragmentActivity activity)方法UI在线程下的实现

//RequestManagerRetriever.java
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  if (Util.isOnBackgroundThread()) {
    //如果是非UI线程,则调用get(Context context)方法,并传入Application Context
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    //注意这个地方,调用的是getSupportFragmentManager()方法;
    //在get(Fragment fragment)方法实现中,fm = fragment.getChildFragmentManager();
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

@NonNull
private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
  SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
  RequestManager requestManager = current.getRequestManager();
  if (requestManager == null) {
    Glide glide = Glide.get(context);
    //创建RequestManager并将SupportRequestManagerFragment中的Lifecycle对象引用作为参数传入
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    if (isParentVisible) {
      requestManager.onStart();
    }
    //给SupportRequestManagerFragment设置RequestManager,这样RequestManager
    //和SupportRequestManagerFragment就关联起来了。
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
    @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
  SupportRequestManagerFragment current =
      //判断是否已经添加过Tag为FRAGMENT_TAG的Fragment
      (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  if (current == null) {
    current = pendingSupportRequestManagerFragments.get(fm);
    if (current == null) {
      //创建SupportRequestManagerFragment对象,SupportRequestManagerFragment是没有界面的Fragment
      current = new SupportRequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      pendingSupportRequestManagerFragments.put(fm, current);
      //调用add()方法时也没有传一个layout id,所以这个Fragment对用户是完全不可见的
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

这个过程可总结为:

  • 判断当前FragmentActivity上是否已经添加了Tag为FRAGMENT_TAG的Fragment
  • 如果没有,则创建一个没有界面的SupportRequestManagerFragment对象,并将它add到当前FragmentActivity;然后创建RequestManager对象,并将该对象引用传给SupportRequestManagerFragment对象。 SupportRequestManagerFragment的构造方法中会创建ActivityFragmentLifecycle对象,SupportRequestManagerFragment生命周期发生变化时会调用ActivityFragmentLifecycle中对应生命周期方法。RequestManager实现了LifecycleListener接口,当创建RequestManager对象时会向SupportRequestManagerFragment中的ActivityFragmentLifecycle注册LifecycleListener,所以当ActivityFragmentLifecycle中的生命周期方法发生变化时,RequestManager就能感知到。

对于RequestManagerRetriever的其他get()方法,逻辑基本一样,这里就不展开。接下来我们看下RequestManager对Request的管理方式。

RequestManager对Request管理

类关系

在看RequestManager对Request管理之前,我们先来了解下与RequestManager相关的类图
Glide源码分析——Request管理

RequestManager相关的类图如上,稍微解释下他们直接的关系。

  • RequestManagerRetriever根据get()方法中的参数返回RequestManager对象;

  • RequestManager实现了LifestyleListener接口,并持有Lifecycle和ReqeustTracker对象的引用;

  • Lifecycle接口有两个实现类:ApplicationLifecycle和ActivityFragmentLifecycle,两者的区别是前者只在addListener()就会回调LifecycleListener.onStart()方法,而且也没有调用onStop和onDestroy()方法的地方。这就是说如果你在Fragment/Activity中点用Glide.with()传入的是Application Context时,这个请求不受Fragment/Activity生命周期的影响,会得到执行;但是不建议这么做,因为当界面消失后继续加载也没有意义。

  • SupportRequestManagerFragment持有RequestManager和ActivityFragmentLifecycle对象的引用;

  • 每个加载图片的请求会被封装成一个Reqeust对象;Request由ReqeustTracker管理,而ReqeustTracker对Request的管理是由RequestManager驱动的。

  • RequestManager对Reqeust间接地管理又是受SupportRequestManagerFragment的生命周期影响,所以最终SupportRequestManagerFragment的生命周期作用着图片加载请求。

RequestManager和Fragment/Activity的关系

在对RequestManager关系类图有一定了解后,我们再看下RequestManager、Fragment/Activity和SupportRequestManagerFragment之间的关系。细心的同学在看RequestManager对象创建应该能略知一二,他们的关系如下图所示:
Glide源码分析——Request管理

当我们在Activity/Fragment中调用Glide.with().load(url).into(imageView)并传入Activity/Fragment对象引用作为with参数时,会在对应的Activity/Fragment创建一个SupportRequestManagerFragment并add到Activity/Fragment。注意,这里说的Glide.with()参数是指当前Activity/Fragment对象的引用。从图中能明显看出Activity/Fragment、SupportRequestManagerFragment和RequestManager之间的关系。我们以上面图对应的代码为例,MyActivity中通过Glide加载图片并显示(with()方法传入的为MyActivity对象引用);在MyActivity中add一个MainFragment,MainFramgent中又add一个SubFragment,在两个Fragment中都通过Glide加载图片并显示且with()传入的都是他们对应的引用。

关于他们之间的关系我们可以通过MAT工具来验证

首先dump出堆内存文件,并通过hprof-convert转换成MAT工具能识别的文件(关于dump堆内存文件和MAT工具使用可参考《Android 应用内存泄漏分析(实战篇)》)。通过MAT工具打开,在Histogram界面过滤SupportRequestManagerFragment,可以看到该类有三个实例对象,和上面的关系图对应上了。
Glide源码分析——Request管理
接着通过选中对象,然后右键List objects > with outgoing reference 查看三个SupportRequestManagerFragment实例持有了哪些对象的引用
Glide源码分析——Request管理
Glide源码分析——Request管理
从上面的第二张图可以看出,每个SupportRequestManagerFragment对象持有一个不同FrequestManager对象的引用,并且SupportRequestManagerFragment@0x13c0f6a0、SupportRequestManagerFragment @ 0x13c0e540的mParentFragment分别指向MainFragment和SubFramgent对象;至于SupportRequestManagerFragment @ 0x13c0e698,它是MyActivity中的SupportRequestManagerFragment 对象,它的mParentFragment则为null,这一点可以从下图得到验证
Glide源码分析——Request管理

在有前面的基本认知后,现在再来看下RequestManager是如何管理Request

RequestManager如何管理Request

Glide源码分析——Request管理

RequestManager对Request的管理整体流程很简单,主要分为以下几个步骤:

  • SupportRequestManagerFragment对象创建时会创建ActivityFragmentLifecycle对象;RequestManager对象创建时会向SupportRequestManagerFragment中的ActivityFragmentLifecycle注册LifecycleListener回调。
  • 当SupportRequestManagerFragment生命周期发生变化时(onStart、onStop、onDestroy)调用ActivityFragmentLifecycle中对应的生命周期方法,在这些方法中会调用LifecycleListener中的方法,从而RequestManager就能根据SupportRequestManagerFragment的生命周期对Request进行管理。

到此,我们已经知道RequestManager的创建以及对Request的管理方式,最后稍稍总结下:

  • RequestManager是用来管理图片加载请求(Request);
  • RequestManager对象的创建依赖与Glide.with()调用的线程和传入的参数。对于在非UI线程下调用和参数为Application Context情况下,则先判断是否已创建Application Context对应的RequestManager对象,没有则创建,有则返回该对象引用。对于参数为FragmentActivity和Fragment(指support或者androidx包中的Fragment),会判断它是否包含*面的SupportRequestManagerFragment,如果有则通过SupportRequestManagerFragment.getRequestManager()返回RequestManager对象引用;如果没有则先创建SupportRequestManagerFragment对象,并将它add到FragmentActivity/Fragment中,然后创建RequestManager对象,并向SupportRequestManagerFragment中的ActivityFragmentLifecycle注册LifecycleListener,最后返回创建的对象引用。对于参数为Activity和android.app.Frament,原理和FragmentActivity/Fragment一样,只是创建的Fragment对象是RequestManagerFragment。
  • 当FragmentActivity/Fragment(Activity/android.app.Fragment)生命周期发生变化时,其界面上的SupportRequestManagerFragment生命周期也会发生变化,当SupportRequestManagerFragment发生变化时,会通过ActivityFragmentLifecycle通知LifecycleListener接口实现者RequestManager,RequestManager根据SupportRequestManagerFragment的生命周期变化对Request做出相应的管理。

能学到什么

感知Activity/Fragment的生命周期的方法

 对Request的管理需要定义个RequestManager类,这有一定工作经验的同学都能想到。在这里更值得学习的是感知Activity/Fragment都生命周期的方法,Glide就使用了一个很巧妙的方法来感知Activity/Fragment的生命周期,它通过在Activity/Fragment中添加一个*面的Fragment(SupportRequestManagerFragment或者RequestManagerFragment),RequestManager根据这个Fragment的生命周期变化由来管理Request请求。在早期的Jetpack(当时叫法还是“Android架构组件”) ViewModel也是跟一个没有界面的HolderFragment绑定,从推出的时间来看,Jetpack可能借鉴了Glide;不过最新的Jetpack中已经抛弃了创建一个*面的做法了,因为后面把Fragment、ViewModel、Lifecycle等整合到androidx包之后,就可以直接修改Fragment了。不过对于我们开发者而言,这种感知Activity/Fragment生命周期的方法还是值得借鉴的,特别是当你做自己的框架而又不想依赖第三方库的时候。

上一篇:Android MVVM框架搭建(五)Navigation + Fragment + BottomNavigationView


下一篇:4.2在activity中简单添加2个fragment