天天看點

位元組跳動一面之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的生命周期也會和整個應用程式一樣。

以上就是位元組面試後總結的幾個要點,還不會的同學趕緊學起來吧,感謝您的閱讀,創造不易,如果您覺得本篇文章對您有幫助,請點選關注小編,您的支援就是小編創作的最大動力!

繼續閱讀