Glide作为一个优秀的图片加载框架,有很多值得我们学习的地方,这次我们来看看它是如何管理图片加载的请求吧;特别是它是如何感知Activity/Fragment的生命周期的方式。
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种情况:
除了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)); } }
我们先看非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对象引用,至于为什么要注意,我们后面再讲。
接下来,看下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; }
这个过程可总结为:
FRAGMENT_TAG
的Fragment对于RequestManagerRetriever的其他get()方法,逻辑基本一样,这里就不展开。接下来我们看下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关系类图有一定了解后,我们再看下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的管理方式,最后稍稍总结下:
对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生命周期的方法还是值得借鉴的,特别是当你做自己的框架而又不想依赖第三方库的时候。