Glide源碼分析-生命周期管理

聲明:我目前分析的源碼是最新的Glide源碼:4.12.0版本

implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

1. Glide簡介

Glide是一個支持拉取,解碼和展示視頻快照,圖片,和GIF動畫的框架,正如它的名字翻譯一樣:滑翔。讓用戶加載任何形式的圖片列表盡可能地變得更快、更平滑。

Glide 使用簡明靈活的流式語法API,允許你在大部分情況下一行代碼搞定需求:

Glide.with(fragment)
     .load(url)
     .into(imageView);

默認情況下,Glide使用的是一個定制化的基于HttpUrlConnection的棧,但同時也提供了與Google Volley和Square OkHttp快速集成的工具庫。

2. 性能

Glide 充分考慮了Android圖片加載性能的兩個關鍵方面:

  • 圖片解碼速度

  • 解碼圖片帶來的資源壓力

為了讓用戶擁有良好的App使用體驗,圖片不僅要快速加載,而且還不能因為過多的主線程I/O或頻繁的垃圾回收導致頁面的閃爍和抖動現(xiàn)象。Glide使用了多個步驟來確保在Android上加載圖片盡可能的快速和平滑:

  • 自動、智能地下采樣(downsampling)和緩存(caching),以最小化存儲開銷和解碼次數(shù);
  • 積極的資源重用,例如字節(jié)數(shù)組和Bitmap,以最小化昂貴的垃圾回收和堆碎片影響;
  • 深度的生命周期集成,以確保僅優(yōu)先處理活躍的Fragment和Activity的請求,并有利于應用在必要時釋放資源以避免在后臺時被殺掉。

3. 源碼分析

關于Glide的詳細使用介紹,參見前面鏈接即可,但是分析源碼也要有個開始吧,那我們就從最基本的用法入手,Glide最基本的用法就是三段論:with、load和into。那我們現(xiàn)在就先從with開始。

3.1 生命周期的作用域(1.Application, 2.Activity, 3.Fragment)

//com.bumptech.glide.Glide.java
public static RequestManager with(@NonNull Context context) {
    // getRetriever(context)返回RequestManagerRetriever,下面的生命周期關聯(lián)會用到
    return getRetriever(context).get(context);
}

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

public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
}

public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
}

public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
}

從Glide.with()靜態(tài)方法中,我們可以看到方法可以傳入5個參數(shù):Context、Activity、FragmentActivity、Fragment或者View。按照作用域分,我們可以把它分成兩類:Application類和非Application類。

  • Application類:它的生命周期是全局的,沒有空白Fragment就綁定Activity/Fragment。
  • 非Application類,它的生命周期跟隨Activity和Fragment的生命周期,專門有一個空白Fragment綁定Activity/Fragment。

從上面with的重載方法看出都會調(diào)用到getRetriever()方法,他其實最終就是返回RequestManagerRetriever對象,緊接著,我們看看RequestManagerRetriever的get方法。這里先分兩個來看:

  • Activity、FragmentActivity、Fragment和View
  • Context
3.1.1 Activity類的get()
public RequestManager get(@NonNull Activity activity) {
  if (Util.isOnBackgroundThread()) {
       //如果不是UI線程,生命周期劃分到Application
    return get(activity.getApplicationContext()); 
  } else if (activity instanceof FragmentActivity) {
    return get((FragmentActivity) activity);
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    android.app.FragmentManager fm = activity.getFragmentManager();
    // 不管是Activity、FragmentActivity、Fragment和View的get(),最終都會調(diào)用到fragmentGet()
    return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}
//最終with返回綁定了代理Fragemnt的RequestManager
private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //創(chuàng)建一個沒有UI的空Fragment來監(jiān)控用戶自定義的Activity生命周期
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      //創(chuàng)建Glide實例
      Glide glide = Glide.get(context);
      //綁定Glide和空白的Fragemnt
      //注意?。?這里創(chuàng)建RequestManager的時候會傳入Lifecycle,后面會根據(jù)這個lifecycle來透傳fragment的生命周期給Glide
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
3.1.2 Context類的get()
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)) {
    // 如果在UI線程,并且是3.1.1小節(jié)的組件,就調(diào)用Activity類的get(),返回綁定了空Fragment的requestManager
    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());
    }
  }
  // 作用域是Application返回的返回綁定了空Fragment的requestManager
  return getApplicationManager(context);
}

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) {
          //生命周期和Application一致
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }
    return applicationManager;
  }
3.1.3 小結

Glide的with()生命周期總結如下圖

作用域總結.png
  • 子線程中Glide調(diào)用get()、傳入ApplicationContext和ServiceContext,對應的生命周期屬于Application域,生命周期和Application一致
  • Activity、Fragment和View對應的生命周期是被代理Fragemnt監(jiān)控的,Glide內(nèi)部邏輯會根據(jù)Activity的生命周期做相應調(diào)整

3.2 Glide生命周期感知過程

如3.1.1小節(jié)中分析的,不管with傳入的是fragment、Activity還是View,RequestManagerRetriever都會創(chuàng)建一個沒有UI的Fragment(SupportRequestManagerFragment)來當代理,當用戶自定義的Activity或者Fragment生命周期發(fā)生變化的時候,Glide內(nèi)部可以通過代理Fragment知道生命周期發(fā)生的變化,因此內(nèi)部也做相應的處理。例如下載并且加載是一個比較耗時操作,如果下載完成之后,Activity已經(jīng)被銷毀了,那就不用加載了,所有這就是Glide感知組件生命周期的意義,用戶不用主動調(diào)用clear()方法來釋放資源了。關聯(lián)關系如下圖。

生命周期與組件關聯(lián).png

3.3 Glide與空Fragment綁定過程

從3.1.3小結中可以知道,只有在主線程中調(diào)用with()并且傳入Activity或者Fragment會綁定空Fragment。當傳入的activity,這個activity上覆蓋的空Fragment是RequestManagerFragment;當傳入的是fragment,覆蓋在上面的空fragment是SupportRequestManagerFragment。邏輯都是一樣的,下面以傳入fragment來分析。

/** Pending adds for SupportRequestManagerFragments. 
* 空Fragment(SupportRequestManagerFragment)與FragmentManager的映射關系
*/
  final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments = new HashMap<>();

private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    // 從三個地方去拿空Fragment,緊接著會分析
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    // 從空Fragment中拿到requestManager
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // 實例化glide用于在創(chuàng)建requestManager的時候綁定glide
      Glide glide = Glide.get(context);
      // 創(chuàng)建requestManager并且綁定glide
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      //如果父fragment可見,就通知glide的onStart()
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
}

private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    // 第一個地方:先從FragmentManager中去拿
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      // 第二個地方:從內(nèi)存中去拿
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        //以上兩個地方都沒有,就創(chuàng)建一個空Fragment然后返回
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        //記錄映射關系在內(nèi)存中,臨時存的
        pendingSupportRequestManagerFragments.put(fm, current);
        //提交Fragment事務
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //如果提交成功之后就刪除臨時存的映射關系
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

從supportFragmentGet()方法中我們看到了Glide內(nèi)部邏輯和空Fragment的綁定過程。

不知道大家有沒有疑惑:為什么在getSupportRequestManagerFragment()方法中要在pendingSupportRequestManagerFragments中臨時保存空Fragment?

其實就是為了避免 SupportRequestManagerFragment 在一個作用域中重復創(chuàng)建。
因為commitAllowingStateLoss() 是將事務 post 到消息隊列中的,也就是說,事務是異步處理的,而不是同步處理的。假設沒有臨時保存記錄,一旦在事務異步等待執(zhí)行時調(diào)用了Glide.with(...) ,就會在該作用域中重復創(chuàng)建 Fragment。

3.4 生命周期的詳細監(jiān)聽過程

從上面小節(jié)分析可以看出,生命周期的管理,主要對Activity、Fragment和View(實質(zhì)也是Activity或Fragment)有效,其他的都是Application域,沒必須分析。所以后面的分析都是基于Activity或者Fragment的生命周期,而這兩個邏輯都是一樣的,我們還是以Fragment的分析為例。

從前面看出,每個Activity或者Fragment域都會創(chuàng)建一個空Fragment蓋在上面。下來我們就從這個空Fragment開始分析Glide的生命周期是如何受影響的。Fragment蓋的空Fragment是SupportRequestManagerFragment.java,那我們就從這里開始。

public class SupportRequestManagerFragment extends Fragment {
  private final ActivityFragmentLifecycle lifecycle;
    
  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
    
  @Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }
    
  ActivityFragmentLifecycle getGlideLifecycle() {
    return lifecycle;
  }
  ......  
}

從3.1.1小節(jié)可以看到,創(chuàng)建RequestManager時是通過工廠創(chuàng)建的,那我們在看看這個工廠

//RequestManagerRetriever.java中
//創(chuàng)建Glide實例
Glide glide = Glide.get(context);
requestManager =factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);

//factory接口
public interface RequestManagerFactory {
    @NonNull
    RequestManager build(
        @NonNull Glide glide,
        @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode,
        @NonNull Context context);
  }

//默認的RequestManager工廠
private static final RequestManagerFactory DEFAULT_FACTORY =
    new RequestManagerFactory() {
    @NonNull
    @Override
    public RequestManager build(
        @NonNull Glide glide,
        @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode,
        @NonNull Context context) {
        return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
    }
};

RequestManager工廠在創(chuàng)建RequestManager的時候,傳入了glide和lifecycle,在RequestManager中完成綁定。

public class RequestManager
    implements ComponentCallbacks2, LifecycleListener,...{
    
    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的生命周期回調(diào)加入到RequestManager中
        lifecycle.addListener(this);
      }

      ......
    }
    
    public synchronized void onStart() {
        resumeRequests();
        // targetTracker維持著Traker列表,每個Traker屬于Glide內(nèi)部需要監(jiān)聽生命周期的邏輯
        targetTracker.onStart();
    }
    
    public synchronized void onStop() {
        pauseRequests();
        targetTracker.onStop();
    }
}

至此,生命周期的詳細監(jiān)聽過程就通了。

總結:調(diào)用with()創(chuàng)建RequestManager,創(chuàng)建RequestManager傳入Lifecycle對象(這個對象是在無界面 Fragment 中創(chuàng)建的),RequestManager通過Lifecycle通知Glide內(nèi)部的各個業(yè)務Traker。

當 Fragment 的生命周期變化時,無界面 Fragment會感知到生命周期變化,然后通過Lifecycle 對象將事件分發(fā)到 RequestManager,RequestManager的onStart()將事件分發(fā)給targetTracker,targetTracker分發(fā)給Glide內(nèi)部邏輯。

參考文檔:

1.Glide簡介

2.郭霖關于Glide的源碼分析

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容