code小生 一个专注大前端领域的技术平台公众号回复Android
加入安卓技术群
作者:唠嗑008
链接:https://www.jianshu.com/p/79dd4953ec25
声明:本文已获唠嗑008
授权发表,转发等请联系原作者授权
熟悉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时,初始化Lifecycle、LifecycleListener,并且在生命周期的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把它删除,这是什么情况?
原因是这样的,当调用FragmentManager的add()方法时,是通过开启事务的方式来进行绑定的,这个过程是异步的,具体来说,就是调用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,那么代码流程应该是这样的
此时通过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
相关阅读
1 Android项目重构实践:从 Fresco 到 Glide 低成本重构方案
2 Glide 架构设计艺术
3 Android Glide缓存策略分析
4 Android 基于 glide 4.0 封装图片加载库
5 Glide 加载图片实现进度条效果
如果你有写博客的好习惯
点个在看,小生感恩❤️