Glide作为一个优秀的图片加载框架,有很多值得我们学习的地方,这次我们来看看它是如何管理图片加载的请求吧;特别是它是如何感知Activity/Fragment的生命周期的方式。
文章目录
在Glide中会把每个图片加载请求封装成一个Request对象,而这些Request对象的管理里是RequestManager。在了解Request Manager对Request管理之前,我们先来看下Glide请求显示过程,请求过程大致如下时序图所示:
时序图中省略了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相关的类图
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对象创建应该能略知一二,他们的关系如下图所示:
当我们在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,可以看到该类有三个实例对象,和上面的关系图对应上了。
接着通过选中对象,然后右键List objects > with outgoing reference 查看三个SupportRequestManagerFragment实例持有了哪些对象的引用
从上面的第二张图可以看出,每个SupportRequestManagerFragment对象持有一个不同FrequestManager对象的引用,并且SupportRequestManagerFragment@0x13c0f6a0、SupportRequestManagerFragment @ 0x13c0e540的mParentFragment分别指向MainFragment和SubFramgent对象;至于SupportRequestManagerFragment @ 0x13c0e698,它是MyActivity中的SupportRequestManagerFragment 对象,它的mParentFragment则为null,这一点可以从下图得到验证
在有前面的基本认知后,现在再来看下RequestManager是如何管理Request
RequestManager如何管理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生命周期的方法还是值得借鉴的,特别是当你做自己的框架而又不想依赖第三方库的时候。