1. 程式人生 > >Glide 原始碼分析(一)

Glide 原始碼分析(一)

Glide原始碼分析

寫在前面

在專案開發中一直使用Glide進行圖片的載入顯示,知道如何使用,但不清楚Glide內部是如何實現的。所以一直想看看Glide的原始碼實現是如何做的,終於有時間和機會了,寫下來做個筆記,也給大家學習下。

Glide載入基本步驟

一般而言,我們要載入並顯示一張圖片只需要一行程式碼,如下所示:

Glide.with(Context).load(source).into(target);

很簡單的一行程式碼,但是具體Glide中做了什麼操作,怎麼操作。我們也要進一步瞭解下。

原始碼下載

如果是用新增依賴的方式將Glide引入到專案中的,原始碼就已經下載下來了,在Android Studio中就可以直接進行檢視。 使用新增依賴的方式引入的Glide,只能看原始碼,不能修改原始碼,如果想修改原始碼,可以在GitHub上面將完整原始碼下載下來。

在網上看到大神分析Glide原始碼是3.7.0版本,因為Glide已經更新很多版本了,雖然大部分相同,可是也有細微差異。 所以我這邊分析用的原始碼是4.8.0,需要下載原始碼的點這裡:https://github.com/bumptech/glide/releases/tag/v4.8.0

開始閱讀

按照上面說的Glide的載入步驟,就是三步:先with(),再load(),最後into()。那麼我們開始一步步閱讀這三步走的原始碼,先從with()看起。

  public static RequestManager with(@NonNull Context context) {
    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.getActivity()).get(fragment);
  }
  
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }
  
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

with() 是一組過載的靜態方法,每個with()方法傳入的引數不同,有fragment、activity、context三種引數。 with() 返回的是RequestManager,所以應該可以猜到,接下來的load()的操作肯定是在RequestManager 中進行。 with() 內部呼叫了getRetriever(),然後又呼叫了get方法。一般,單例模式都是用get方法返回唯一例項的,所以可以想到在get中返回了RequestManager物件 。

getRetriever()中的邏輯是什麼?又做了什麼操作?進來看看。

  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    ...
    return Glide.get(context).getRequestManagerRetriever();
  }

getRetriever返回型別是RequestManagerRetriever。 在方法內部呼叫Glide的get方法返回單例物件,再呼叫Glide的getRequestManagerRetriever方法,返回RequestManagerRetriever。我們進Glide的get中看具體做了什麼操作。

/**
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }

get是靜態方法,返回型別為Glide。 在方法內部採用雙重鎖檢測機制(DCL,單例模式的實現方法之一)檢查並初始化Glide後返回glide唯一例項,glide變數在宣告的時候用volatile關鍵字修飾。再進一步看如何進行檢查和初始化Glide的。

private static void checkAndInitializeGlide(@NonNull Context context) {
    // In the thread running initGlide(), one or more classes may call Glide.get(context).
    // Without this check, those calls could trigger infinite recursion.
    if (isInitializing) {
      throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
          + " use the provided Glide instance instead");
    }
    isInitializing = true;
    initializeGlide(context);
    isInitializing = false;
  }

在方法內呼叫initializeGlide(context),在initializeGlide(context)中又呼叫了initializeGlide(context, new GlideBuilder())。


  @SuppressWarnings("deprecation")
  private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext();
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      manifestModules = new ManifestParser(applicationContext).parse();
    }
	...
	移除相同的GlideModule
	...
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
    ...
    設定Glide Builder
    ...
    Glide glide = builder.build(applicationContext);
    ...
    //註冊元件
    ...
    //註冊記憶體優化的系統回撥
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }

到目前為止,glide的初始化已完成,我們拿到了glide的唯一例項。 然後返回到上面的getRequestManagerRetriever,繼續跟蹤它內部是什麼邏輯。

  @NonNull
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }

拿到Glide的成員變數requestManagerRetriever,繼續返回上一步,跟蹤它的get方法中是什麼邏輯

@NonNull
  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) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

在這裡,我們可以看到with傳進來的引數派上用場了,根據context的型別走不同的分支。 如果context是null,則直接丟擲異常。如果不是在主執行緒或者傳進來的context是Application型別則返回getApplicationManager,Application物件的生命週期就是應用的生命週期,這種情況下它和應用的生命週期是同步的,在應用關閉退出的時候,Glide的載入也會自動終止。如果不是上面的情況則根據context的型別執行對應的執行get()方法。


  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
          "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
  }

可以看到,如果是在後臺執行緒中,則按Application型別處理。不管傳進來是Activity還是fragment,在get方法中最終都呼叫了supportFragmentGet方法,

@NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(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;
  }

在supportFragmentGet方法中建立了一個沒有介面的fragment,它的生命週期和context保持一致,這樣context在銷燬的時候,fragment可以檢測到這個銷燬操作,那麼Glide的載入在fragment銷燬的時候也會同步停止。最終返回了requestManager例項。至此with的流程走完了,與咱們開頭看到的with方法返回RequestManager型別的結果是一致的。