轉載請註明出處:王亟亟的大牛之路
寫之前先安利,接下來2 3個月我會花點時間撿起一些安卓的技能,看看這2年沒花什麼精力投入的安卓變成啥樣子了https://github.com/ddwhan0123/Useful-Open-Source-Android
什麼是Glide?
Glide是一個快速高效的Android圖片加載庫,注重於平滑的滾動。Glide提供了易用的API,高性能、可擴展的圖片解碼管道(decode pipeline),以及自動的資源池技術。
Glide 支持拉取,解碼和展示視頻快照,圖片,和GIF動畫。Glide的Api是如此的靈活,開發者甚至可以插入和替換成自己喜愛的任何網絡棧。默認情況下,Glide使用的是一個定製化的基於HttpUrlConnection的棧,但同時也提供了與Google Volley和Square OkHttp快速集成的工具庫。
雖然Glide 的主要目標是讓任何形式的圖片列表的滾動儘可能地變得更快、更平滑,但實際上,Glide幾乎能滿足你對遠程圖片的拉取/縮放/顯示的一切需求。
本篇研究的內容和目的
- Glide如何暫停請求
- Glide如何獲取生命週期
- 以上二者是如何實現的
入口方法
Glide.with(this).load(img_url).into(imageView)
簡單的一句加載函數
.with()
關聯了一個上下文環境的對象
.load()
關聯了你要加載的資源的路徑(load是一個多態的方法,可以是url,字符串地址,文件等等等方式)
.into()
是把以上的內容加載到哪個控件裏去(into()方法也是,面向的是ViewTarget<a,b>的泛形)
with的做了什麼
所有with方法都返回了一個RequestManager
對象
RequestManager的get方法會根據不同的入參類型去構建RequestManager
對象(以下以Activity的場景爲例)
@NonNull
public RequestManager get(@NonNull Activity activity) {
//判斷是否在前臺,否則調用更大引用週期的上下文對象
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//有效生命週期內才繼續初始化流程
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//傳入4個參數上下文對象,activity的FragmentManager實現,空,true(是否前臺可見)
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
fragmentGet方法是實質構建RequestManager對象的方法,無論如何不會爲空返回
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
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;
}
RequestManager
我們來看一下這個類的源碼,看下他是如何實現的。
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {}
實現了LifecycleListener
接口,也就是onDestroy,onStart,onStop
幾個方法的回調都能拿到,可以在其中實現自己的業務邏輯
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 (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
//glide整個的請求管理託付於這個類
glide.registerRequestManager(this);
}
構造函數獲取了Glide和之前由最外層context初始化的RequestManagerFragment的一些屬性,當然初始化的時候還有一些靜態內部的常量,構建了RequestOptions的一些屬性
接下來看一下這個類實現了哪些功能(只解釋跟我們主題相關的)
判斷當前上下文對象的生命週期是否處於暫停狀態
public synchronized boolean isPaused() {
return requestTracker.isPaused();
}
暫停正在執行中的請求
public synchronized void pauseRequests() {
requestTracker.pauseRequests();
}
暫停請求,且清楚已完成的加載內容
public synchronized void pauseAllRequests() {
requestTracker.pauseAllRequests();
}
恢復所有未完成的請求
public synchronized void resumeRequests() {
requestTracker.resumeRequests();
}
@Override
public synchronized void onStart() {
//恢復請求
resumeRequests();
targetTracker.onStart();
}
@Override
public synchronized void onStop() {
//暫停請求
pauseRequests();
targetTracker.onStop();
}
回收資源,移除監聽
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
這裏看到RequestTracker其實是RequestManager實現的代理。我們找了3層終於了具體實現生命週期回調,和調用終止/恢復請求的地方。
RequestTracker
沒有帶參的構造函數,內部維護了請求隊列
public class RequestTracker {
private static final String TAG = "RequestTracker";
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
}
在調用into()方法後會被執行,Request是個接口,實現了請求,取消,暫停等功能方法
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
暫停請求,並回收
public boolean clearRemoveAndRecycle(@Nullable Request request) {
return clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ true);
}
在初次啓動請求時會設置爲false,是否暫停請求的控制flag
public boolean isPaused() {
return isPaused;
}
在容器生命週期onStop()回調中恢復請求暫停請求
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.clear();
pendingRequests.add(request);
}
}
}
在容器生命週期onStart()回調中恢復請求
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
清除請求並回收,在上下文生命週期的onDestroy()處調用
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ false);
}
pendingRequests.clear();
}
在網絡監聽到連接的狀態下,重新請求,包括失敗的/暫停的/進行中的
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCleared()) {
request.clear();
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
}
總結
第一步:with方法掛載上下文對象用以獲取他的生命週期,並初始化RequestManager對象。
第二部:RequestManager對象初始化了RequestOptions,以及實現一系列生命週期與業務邏輯相關聯的方法,並且實現了.load()方法,把資源方面的實現與上下文相關業務實現分離。
第三部:RequestManager用自己的代理實現RequestTracker類維護了未完成和完成兩個任務隊列,通過Request接口分別實行不同的業務方法
簡要知識點:
調用into()方法後纔會開始執行業務請求
網絡狀態已經實現監聽,業務端不用自己監聽後調用clear()
Glide網絡監聽接口只區分斷沒斷網,不管理網絡類型(暫未發現對4g/3g/2g/wifi等場景的特殊處理)
其他
有問題歡迎溝通,但請註明來意