Glide4.x 任務與上下文生命週期關聯的實現分析

轉載請註明出處:王亟亟的大牛之路

寫之前先安利,接下來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等場景的特殊處理)

其他

有問題歡迎溝通,但請註明來意
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章