位元組跳動一面之Glide生命週期管理面試總結

本文透過在位元組面試遇到的問題總結而出,如有不對的地方,請及時批評指正。篇幅較長,請耐心閱讀。如果您想了解其他框架原始碼,歡迎評論區留言!

篇幅較長,請耐心閱讀[玫瑰]

簡介

Glide是一個優秀的圖片載入框架,支援多種資料來源,功能強大,效能高。如圖所示:

位元組跳動一面之Glide生命週期管理面試總結

使用步驟

1。在build。gradle中新增glide引用

implementation ‘com。github。bumptech。glide:glide:4。12。0’

2。使用glide載入圖片

Glide。with(this)。load(BASE_PIC_URL)。into(img_user)

原始碼分析

設計模式

1。單例模式

位元組跳動一面之Glide生命週期管理面試總結

Glide使用了單例設計模式,透過雙重校驗鎖機制不僅保證了Glide物件的全域性單例,而且解決了多執行緒環境下的併發安全問題。

2。工廠設計模式

位元組跳動一面之Glide生命週期管理面試總結

Glide內部的建立RequestManager物件時使用了工廠設計模式,透過定義RequestManagerFactory抽象介面,讓其子類建立RequestManager物件,隱藏其內部建立邏輯。

3。建造者設計模式

位元組跳動一面之Glide生命週期管理面試總結

位元組跳動一面之Glide生命週期管理面試總結

Glide使用了靜態類GlideBuilder構建Glide物件,將Glide的各種屬性封裝到GlideBuilder中,根據不同的屬性設定構建不同功能的Glide物件。簡化Glide的構建過程。

生命週期繫結

主執行緒中使用

位元組跳動一面之Glide生命週期管理面試總結

1

.Glide

使用

With

方法傳入所需要的上下文,主執行緒中一般傳

context

fragment

activity

來實現對生命週期的繫結。

public static RequestManager with(@NonNull Context context) public static RequestManager with(@NonNull Activity activity) public static RequestManager with(@NonNull Fragment fragment) public static RequestManager with(@NonNull FragmentActivity activity)

2 。下面以

activity

為例,引數傳入activity。

public static RequestManager with(@NonNull Activity activity) { return getRetriever(activity)。get(activity); }

3 。透過呼叫

RequestManagerRetriever

get

方法,傳入activity引數返回

RequestManager

物件。

RequestManager

主要負責管理Glide的請求和啟動。

@NonNull public RequestManager get(@NonNull Activity activity) { //判斷是否是後臺執行緒 if (Util。isOnBackgroundThread()) { return get(activity。getApplicationContext()); } else if (activity instanceof FragmentActivity) { return get((FragmentActivity) activity); } else { //判斷當前activity沒有被銷燬,否則丟擲異常 assertNotDestroyed(activity); frameWaiter。registerSelf(activity); //獲取activity中的FragmentManager android。app。FragmentManager fm = activity。getFragmentManager(); //透過fragmentGet方法 ,建立並返回 RequestManager return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } }

RequestManagerRetriever

get

方法中根據傳入的引數不同,使用

Util.isOnBackgroundThread

判斷子執行緒和主執行緒分別進行不同的處理。主執行緒中最終都是呼叫

fragmentGet

方法。

注意

,由於這裡的引數是

activity

,獲取的是

fragmentManager

,如果傳入的是

fragment

,則獲取的

childFragmentManager

4

.fragmentGet

方法主要是透過

RequestManagerFragment

來獲取

RequestManager

,如果沒有獲取到,則透過

工廠模式

進行建立。同時傳入fragment的

getGlideLifecycle

這個lifecycle是重點,需要注意

private RequestManager fragmentGet( @NonNull Context context, @NonNull android。app。FragmentManager fm, @Nullable android。app。Fragment parentHint, boolean isParentVisible) { //透過fragmentManager獲取RequestManagerFragment RequestManagerFragment current = getRequestManagerFragment(fm, parentHint); //獲取RequestManagerFragment中的requestManager RequestManager requestManager = current。getRequestManager(); //判斷requestManager if (requestManager == null) { //如果requestManager為空,則透過工廠設計模式創建出requestManager Glide glide = Glide。get(context); requestManager = factory。build( glide, current。getGlideLifecycle(), current。getRequestManagerTreeNode(), context); //如果activity顯示出來,則執行requestManager的onStart方法 if (isParentVisible) { requestManager。onStart(); } current。setRequestManager(requestManager); } return requestManager; }

5 。建立

RequestManagerFragment

,這裡建立一個空白頁面的

RequestManagerFragment

並且繫結到當前activity中。

@NonNull private RequestManagerFragment getRequestManagerFragment( @NonNull final android。app。FragmentManager fm, @Nullable android。app。Fragment parentHint) { //透過tag獲取fragmentManager中儲存的fragment RequestManagerFragment current = (RequestManagerFragment) fm。findFragmentByTag(FRAGMENT_TAG); if (current == null) { //如果獲取不到,則進一步透過 pendingRequestManagerFragments Map中獲取 current = pendingRequestManagerFragments。get(fm); if (current == null) { //如果還是獲取不到,則進行建立 current = new RequestManagerFragment(); current。setParentFragmentHint(parentHint); //同時儲存到map中 pendingRequestManagerFragments。put(fm, current); //然後新增到當前activity中 fm。beginTransaction()。add(current, FRAGMENT_TAG)。commitAllowingStateLoss(); //將這個新增動作透過handler傳送給系統處理 handler。obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm)。sendToTarget(); } } return current; }

6

.RequestManagerFragment

的建構函式建立了

ActivityFragmentLifecycle

用來監聽

RequestManagerFragment

的生命週期

onStart(),onStop(),onDestroy()

public SupportRequestManagerFragment() { this(new ActivityFragmentLifecycle()); }public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this。lifecycle = 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(); }

最後在

fragmentGet方法中

ActivityFragmentLifecycle

透過工廠設計模式傳給

RequestManager

並返回。

7

.ActivityFragmentLifecycle繼承於

Lifecycle介面。

@Override public void addListener(@NonNull LifecycleListener listener) { //所有的監聽者都新增監聽 lifecycleListeners。add(listener); //根據不同的生命週期進行處理 if (isDestroyed) { listener。onDestroy(); } else if (isStarted) { listener。onStart(); } else { listener。onStop(); } } @Override public void removeListener(@NonNull LifecycleListener listener) { //移除所有監聽 lifecycleListeners。remove(listener); } void onStart() { //只新增一次監聽 isStarted = true; //同步所有生命週期 for (LifecycleListener lifecycleListener : Util。getSnapshot(lifecycleListeners)) { lifecycleListener。onStart(); } } void onStop() { isStarted = false; //同步所有生命週期 for (LifecycleListener lifecycleListener : Util。getSnapshot(lifecycleListeners)) { lifecycleListener。onStop(); } } void onDestroy() { isDestroyed = true; //同步所有生命週期 for (LifecycleListener lifecycleListener : Util。getSnapshot(lifecycleListeners)) { lifecycleListener。onDestroy(); } }

8

.RequestManager

拿到這個

lifecycle

,進行繫結監聽

RequestManagerFragment

生命週期。

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; 。。) ……………………。。。 //判斷是否是後臺執行緒 if (Util。isOnBackgroundThread()) { Util。postOnUiThread(addSelfToLifecycle); } else { //新增lifecycle監聽 lifecycle。addListener(this); } lifecycle。addListener(connectivityMonitor); …………。。 }

9 。透過生命週期的繫結處理對應的業務邏輯和資源釋放等功能。

public synchronized void onStart() { //開始請求 resumeRequests(); targetTracker。onStart(); } @Override public synchronized void onStop() { //開始停止 pauseRequests(); targetTracker。onStop(); } @Override public synchronized void onDestroy() { targetTracker。onDestroy(); //釋放資源 targetTracker。clear(); requestTracker。clearRequests(); lifecycle。removeListener(this); lifecycle。removeListener(connectivityMonitor); Util。removeCallbacksOnUiThread(addSelfToLifecycle); glide。unregisterRequestManager(this); }

總結如下圖所示:

位元組跳動一面之Glide生命週期管理面試總結

Glide在主執行緒中使用時,透過建立一個空白的fragment新增到當前Activity/Fragment中,用來監聽當前頁面的生命週期變化,進行圖片的顯示或資源的釋放。

子執行緒中使用

位元組跳動一面之Glide生命週期管理面試總結

1 。 Glide在子執行緒中使用只能傳入applicationContext。

public static RequestManager with(@NonNull Context context)

2 。透過呼叫

RequestManagerRetriever

get

方法,傳入activity引數返回

RequestManager

物件。

RequestManager

主要負責管理Glide的請求和啟動。

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 && ((ContextWrapper) context)。getBaseContext()。getApplicationContext() != null) { return get(((ContextWrapper) context)。getBaseContext()); } } //子執行緒返回applicationManager return getApplicationManager(context); }

3 。在

getApplicationManager

方法中透過

雙重校驗鎖

單例

方式返回

applicationManager

,applicationManager的建立使用了

工廠設計模式

,隱藏了applicationManager的內部建立細節。

@NonNull private RequestManager getApplicationManager(@NonNull Context context) { if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { Glide glide = Glide。get(context。getApplicationContext()); applicationManager = factory。build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context。getApplicationContext()); } } } return applicationManager; }

4

.getApplicationManager建立

applicationManager時傳入了

ApplicationLifecycle

作為生命週期監聽。

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; …………。 //如果是子執行緒,透過使用Handler切換到主執行緒 if (Util。isOnBackgroundThread()) { Util。postOnUiThread(addSelfToLifecycle); } else { lifecycle。addListener(this); } …………。。。。 }

5

.RequestManager

拿到這個

lifecycle

,使用Handler切換到主執行緒進行繫結監聽Application生命週期。

private final Runnable addSelfToLifecycle = new Runnable() { @Override public void run() { lifecycle。addListener(RequestManager。this); } };

6 。透過繫結

Application的onStart()

方法進行請求處理。

public synchronized void onStart() { //開始請求 resumeRequests(); targetTracker。onStart(); }

總結如下圖所示:

位元組跳動一面之Glide生命週期管理面試總結

當Glide在子執行緒中使用時,只需要監聽application的onStart方法進行業務請求的處理,application銷燬時,整個應用程式都會被銷燬,Glide也會跟隨著應用銷燬而進行資源釋放。所以在子執行緒中使用,由於傳入的context是applicationContext,Glide的生命週期也會和整個應用程式一樣。

以上就是位元組面試後總結的幾個要點,還不會的同學趕緊學起來吧,感謝您的閱讀,創造不易,如果您覺得本篇文章對您有幫助,

請點選關注小編

,您的支援就是小編創作的最大動力!