在Glide解析一:Glide整體流程中牍陌,我們知道RequestManager是主要用來管理、啟動圖片加載請求的滥朱。而它是通過RequestManagerRetriever創(chuàng)建苛白、獲取的。
1焚虱、為什么用RequestManagerRetriever來獲取RequestManager购裙?
RequestManagerRetriever.java
為什么用RequestManagerRetriever來獲取RequestManager?而不直接使用RequestManager的單例鹃栽?我們通過常用的使用方式來分析其原因:
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
//如果是在非UI線程躏率,則使用綁定Application生命周期的RequestManager
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(view.getContext(),
"Unable to obtain a request manager for a view without a Context");
//根據(jù)view拿到activity
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
// Support Fragments.
// Although the user might have non-support Fragments attached to FragmentActivity, searching
// for non-support Fragments is so expensive pre O and that should be rare enough that we
// prefer to just fall back to the Activity directly.
//如果使用的是support中的activity
if (activity instanceof FragmentActivity) {
//如果是FragmentActivity
//如果view是support fragment中的躯畴,則根據(jù)view獲取其所在的support fragment,接著調(diào)用get(fragment)
//如果view是FragmentActivity中薇芝,則調(diào)用get(FragmentActivity)方法
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
//如果沒有support中的組件蓬抄,其原理與support中的activity一樣,不展開講解
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
private Fragment findSupportFragment(@NonNull View target, @NonNull FragmentActivity activity) {
//清空view和fragment關(guān)聯(lián)列表
tempViewToSupportFragment.clear();
//從activity的所有fragment中找出fragment的根view夯到,并將根view與fragment進行關(guān)聯(lián)存放view和fragment關(guān)聯(lián)列表tempViewToSupportFragment中
findAllSupportFragmentsWithViews(
activity.getSupportFragmentManager().getFragments(), tempViewToSupportFragment);
Fragment result = null;
View activityRoot = activity.findViewById(android.R.id.content);
View current = target;
while (!current.equals(activityRoot)) {
//從view和fragment關(guān)聯(lián)列表中獲取view所關(guān)聯(lián)的fragment
result = tempViewToSupportFragment.get(current);
if (result != null) {
break;
}
if (current.getParent() instanceof View) {
//獲取當(dāng)前view的父級view
current = (View) current.getParent();
} else {
break;
}
}
tempViewToSupportFragment.clear();
return result;
}
private static void findAllSupportFragmentsWithViews(
@Nullable Collection<Fragment> topLevelFragments,
@NonNull Map<View, Fragment> result) {
if (topLevelFragments == null) {
return;
}
for (Fragment fragment : topLevelFragments) {
//遍歷fragment
// getFragment()s in the support FragmentManager may contain null values, see #1991.
if (fragment == null || fragment.getView() == null) {
continue;
}
//將fragment的根view與fragment進行關(guān)聯(lián)
result.put(fragment.getView(), fragment);
findAllSupportFragmentsWithViews(fragment.getChildFragmentManager().getFragments(), result);
}
}
一般我們都是使用support 中的fragmetactivity嚷缭,所以get(view)要么轉(zhuǎn)到get(Fragment)中要么轉(zhuǎn)到get(FragmentActivity)中。這里先根據(jù)view找到其所在fragment的思路是拿當(dāng)前view的根view與activity的所有fragment的根view進行比較耍贾,如果相等阅爽,則這個fragment就是我們要找的fragment。
1.1荐开、get(Fragment) 的實現(xiàn)邏輯
public RequestManager get(@NonNull Fragment fragment) {
//...
//獲取fragment的子FragmentManager
FragmentManager fm = fragment.getChildFragmentManager();
//調(diào)用supportFragmentGet
return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
}
}
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
//根據(jù)FragmentManager獲取已經(jīng)存在的SupportRequestManagerFragment 或者創(chuàng)建一個新的SupportRequestManagerFragment
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
//獲取與fragment關(guān)聯(lián)的RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
//RequestManager為空
Glide glide = Glide.get(context);
//構(gòu)建一個新的RequestManager
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//將fragment與RequestManager進行關(guān)聯(lián)
current.setRequestManager(requestManager);
}
return requestManager;
}
get(Fragment)獲取SupportRequestManagerFragment 的邏輯我們看下其代碼實現(xiàn):
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
//根據(jù)tag名稱從FragmentManager中查找SupportRequestManagerFragment
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
//如果FragmentManager沒有SupportRequestManagerFragment
//從等待FragmentManager添加Fragment完成列表中獲取SupportRequestManagerFragment
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
////如果沒有SupportRequestManagerFragment
//創(chuàng)建新的SupportRequestManagerFragment
current = new SupportRequestManagerFragment();
//將新創(chuàng)建的fragment加到其父級fragment列表中
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
//如果父級可見付翁,回調(diào)生命周期的onStart
current.getGlideLifecycle().onStart();
}
//將創(chuàng)建的fragment加入等待FragmentManager添加fragment的隊列中
pendingSupportRequestManagerFragments.put(fm, current);
//將創(chuàng)建的fragment加入FragmentManager中
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//發(fā)送消息,從等待FragmentManager添加fragment的隊列中刪除fragment
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
根據(jù)上面的代碼分析可以歸納RequestManagerRetriever創(chuàng)建或者獲取RequestManager的流程:
- 如果在子線程晃听,則創(chuàng)建一個生命周期與Application一樣的RequestManager
- 根據(jù)view先拿到其所屬的fragment或者activity
- 從當(dāng)前framgnet或者activity中獲取RequestManagerFragment百侧,如果不為空則返回與之關(guān)聯(lián)的RequestManager;如果為空那么創(chuàng)建一個新的RequestManagerFragment能扒,創(chuàng)建的情況下順便創(chuàng)建RequestManager,并進行關(guān)聯(lián)佣渴,并返回該RequestManager
根據(jù)這段代碼有2個問題,
問題1:為什么使用pendingSupportRequestManagerFragments來添加RequestManagerManager初斑?fm添加RequestManagerFragment之后又發(fā)送消息刪除該RequestManagerFragment呢辛润?
答案:因為fm添加fragment不是調(diào)用add方法就代表添加完成的,它有相關(guān)的生命周期是異步進行的越平,所以如果add之后立馬又在相同fragment或者activity環(huán)境中調(diào)用get方法频蛔,那么就很有可能又創(chuàng)建一個新的RequestManagerFragment,而pendingSupportRequestManagerFragments就是為了杜絕重復(fù)創(chuàng)建RequestManagerFragment而準(zhǔn)備的秦叛。
問題2:對于glide的get使用有什么優(yōu)化的地方嗎晦溪?
答案: - 盡量不要在子線程中調(diào)用,因為子線程調(diào)用意味著生命周期是全局的挣跋,不能跟activity或fragment的生命周期同步
- get的時候最好傳activity三圆、或者fragment,因為這樣可以減少查找具體的fragment或者activity的步驟
問題3:為什么要用RequestManagerFragment并與RequestManager進行關(guān)聯(lián)呢避咆?
答案:是為了進行自動感應(yīng)組件的生命周期
2舟肉、為什么要用RequestManagerFragment并與RequestManager進行關(guān)聯(lián)?
步驟1中分析了get的流程中查库,fragment和activity最終是通過創(chuàng)建RequestManagerFragment并和RequestManager進行關(guān)聯(lián)
我們看下RequestManagerFragment的幾個關(guān)鍵生命周期函數(shù):
@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();
}
RequestManagerFragment的生命周期相關(guān)的函數(shù)調(diào)用lifecycle對象對應(yīng)的方法路媚,而lifecycle是在SupportRequestManagerFragment構(gòu)造函數(shù)數(shù)中創(chuàng)建的:
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
ActivityFragmentLifecycle內(nèi)部維持了生命周期的監(jiān)聽者列表:
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
//...
}
當(dāng)RequestManagerFragment生命周期變化時,調(diào)用ActivityFragmentLifecycle的對應(yīng)生命周期方法樊销,其實現(xiàn)就是遍歷生命周期監(jiān)聽列表整慎,并調(diào)用監(jiān)聽者對應(yīng)的生命周期方法:
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
那么什么時候添加監(jiān)聽者到ActivityFragmentLifecycle呢脏款?答案是創(chuàng)建RequestManager的時候,我們看下RequestManager構(gòu)成函數(shù):
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
// If we're the application level request manager, we may be created on a background thread.
// In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
// issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
// This should be entirely safe.
if (Util.isOnBackgroundThread()) {
//如果是自線程裤园,則切換到主線程監(jiān)聽生命周期
mainHandler.post(addSelfToLifecycle);
} else {
//監(jiān)聽生命周期
lifecycle.addListener(this);
}
//生命周期變化時撤师,相應(yīng)的監(jiān)聽網(wǎng)絡(luò)狀態(tài)和取消監(jiān)聽網(wǎng)絡(luò)裝
lifecycle.addListener(connectivityMonitor);
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
ok,最后我們總結(jié)下Glide是如何自動感應(yīng)生命周期的:
- 如果是在子線程拧揽,這Glide使用的RequestManager與Application一樣的生命周期
- 如果是fragment剃盾、activity,則使用FragmentManagerFragment與RequestManager進行關(guān)聯(lián),通過FragmentManagerFragment的生命周期變化來調(diào)度RequestManager對圖片加載請求Request采取暫停淤袜、重新開始痒谴、停止等操作。
因為Android有fragment饮怯、support包中的fragment闰歪、activity嚎研、surport中的activity蓖墅,因為使用FragmentManagerFragment來實現(xiàn)RequestManager感應(yīng)生命周期,這幾個fragmengt临扮、activity使用的FragmentManager各自不同,如果是fragment在用ChildFragmentManager或者support中的ChildFragmentManager杆勇;如果是activity則用FragmentManager或者support中的FragmentManager蚜退。所以RequestManagerRetriever主要用來根據(jù)framgnet、activity來創(chuàng)建對應(yīng)的RequestManager蚂且。
問題:Glide中最多有幾個RequestManager杏死?
答案:5個捆交,分別是: - 與Application生命周期一致的RequestManager
- 與app包下activity的FragmentManager關(guān)聯(lián)的RequestManager
- 與app包下fragment的ChildFragmentManager關(guān)聯(lián)的RequestManager
- 與support包下activity的FragmentManager關(guān)聯(lián)的RequestManager
- 與support包下fragment的ChildFragmentManager關(guān)聯(lián)的RequestManager
問題:Glide的get操作有哪些優(yōu)化點品追?
答案: - 在UI線程中調(diào)用肉瓦,可以避免RequestManager生命周期與Application的一直
- 盡量采用support報下的fragment/activity银还;一是因為兼容性洁墙;二是如果統(tǒng)一使用support包下的可以避免創(chuàng)建于與app包下FragmentManager管理的RequestManager
- get盡量傳遞fragment或者activity,這樣可以減少通過view找到具體的fragment或者activity的步驟