【Android面試技巧】當面試官問你glide的時候,是想問什麼?glide生命週期如何實現?

南方吳彥祖_藍斯發表於2020-11-04

去面試的時候,我們也經常被問到這樣的問題:專案用什麼圖片載入框架?為什麼選擇這個框架?glide是現在主流的圖片載入框架,被問到的機率非常高。面試官這樣問,最想聽到的是什麼答案?Lru演算法原理還是三層快取的理解?以我的理解,Lru和三層快取是很基本的,一般的圖片載入框架都用到,這應該不是面試官真正的目的。 面試官最想問的應該是glide最大的優點是什麼?並且能夠針對原始碼講出是怎麼實現的。本篇文章將圍繞這兩個問題去討論。

說在前面的話

glide的原始碼對於我來說,很複雜。一開始覺得雲裡霧裡,後來看了很多遍才理順。寫這篇文章是抓住主線去講述,很多的細節沒有講到,而且是按照我自己認為更好理解的順序去看原始碼。看過原始碼卻還是很暈的朋友們可以看下我的思路,也許有用。如果沒有看過原始碼的,可以去看其它大神寫的關於glide的系列文章,會更好。整篇文章只針對glide的with()傳入Activity環境變數作講解。

glide最大的優點

glide最大的優勢就是對bitmap的管理是跟隨生命週期去發生改變的。其它的框架基本都是用Lru演算法,當Activity銷燬的時候,是不會釋放之前載入圖片佔用的所有記憶體。glide的優勢就是當Activity銷燬的時候,之前載入的所有圖片的記憶體都釋放了。glide是如何做得這一點的,這是我們需要去深挖的地方。

glide如何監聽到Activity的生命週期

在看glide相關資料的時候,知道一個結論,glide是透過新建一個空的Fragment去監聽Activity的生命週期。帶著這個結論然後按呼叫的步驟看原始碼,結果被繞暈了,各種呼叫和類,看了很多次還是很混亂。後來我換個思路,如果簡化的來說,就是新建的Fragment和當前的Activity關聯上,glide根據Fragment的生命週期去做操作, onStart()``發起請求或者重新請求、onStop()暫停請求、``onDestory()`取消清除請求。所以我先找出新建的Fragment,然後順著思路,去檢視它在哪裡和Actvity關聯上。

首先找到Fragment,也就是RequestManagerFragment,內部建立的無UI的Fargment。它在RequestManagerRetriever類的getRequestManagerFragment()被呼叫。相關原始碼:

final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
      new HashMap<>();private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//獲取Fragment
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);//儲存到map集合
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();//新增到Actvity中
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

這部分程式碼涉及FragmentManager的使用,忘了怎麼使用的朋友可以去複習一下。 程式碼不難理解,就是一個目的,得到Fragment並且返回這個Fragment。先透過findFragmentByTag獲取,如果為null,則會從pendingRequestManagerFragments這個Map集合去獲取,如果還是為null,則直接new 一個Fragment,並且儲存到pendingRequestManagerFragments以及新增到Activity中。 這部分的程式碼就是Fragment和Actvity關聯上了,這樣就可以透過Fragment得知當前Activty的生命週期。追蹤RequestManagerFragment,看看它的生命週期裡面做了什麼操作,原始碼如下:

private final ActivityFragmentLifecycle 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();
    unregisterFragmentWithRoot();
  }

Fragment的的生命週期裡(我們只關注貼出程式碼的三個生命週期),ActivityFragmentLifecycle類都呼叫了相同名字的方法,接下來看看ActivityFragmentLifecycle的相應方法裡面有什麼操作。

private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());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();
    }
  }

相應的方法裡都呼叫了LifecycleListener的相關方法,LifecycleListener是一個介面,作用在原始碼裡寫得很清楚: An interface for listener to lifecycle events.,監聽生命週期的介面。既然是個介面,就找出實現它的類,實現LifecycleListener的類是RequestManager。RequestManager類,它實現了LifecycleListener介面,三個方法裡面的內容如下。

/**
   * Lifecycle callback that registers for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
   * requests.
   */
 @Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }
  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }
  /**
   * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
   * all completed requests.
   */
  @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是用來追蹤取消和重新啟動正在進行,已完成和失敗的請求。看到這裡我們可以猜想,RequestManagerFragment生命週期變化的時候回撥RequestManager的onStart、onStop、onDestroy方法,然後Request就做出相應的操作,Activity的生命週期是和Request的生命週期繫結起來。要驗證這個猜想,就要找到RequestManager是怎麼樣監聽到Fragment的生命週期的。我們來看看RequestManager的建立

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);//將Fragment的lifecycle交給RequestManager管理
    }
    return requestManager;
  }

以上程式碼說明,透過工廠模式建立RequestManager,並且將Fragment的lifecycle交給RequestManager管理,程式碼 current.getGlideLifecycle()就是獲取到lifecycle。再回頭去看ReqeustManager,找到了lifecycle操作LifecycleListener的程式碼,在構造器將LifecycleListener新增到lifecycle,原始碼如下:

 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);
   //省略部分程式碼
  }

Lifecycle是用來新增和刪除LifecycleListener,而ReqeustManager的構造方法裡,將LifecycleListener新增到lifecycle裡面。

看到這裡,也就驗證了我們的猜想了。ReqeustManager是來代理管理Request的生命週期方法,也就是請求的生命週期。glide就是透過ReqeustManager監聽到Fragment的生命週期,從而根據生命週期管理讓Request做出相對應的請求。

我們在使用glide的時候很簡單,就是 Glide.with(this).load(url).into(imageView);
glide的with方法返回的也是ReqeustManager類,這個過程中按順序看下來,涉及兩個關鍵方法, fragmentGet()getRequestManagerFragment(),相關的原始碼已經在以上講解中貼出。
下面我將把獲取到ReqeustManager這個過程中涉及的一些重要的方法和類做一些說明,只是我的個人理解,如有不對,歡迎指正。

fragmentGet()

1、呼叫getRequestManagerFragment()得到RequestManagerFragment,也就是Fragment的管理類。 從RequestManagerFragment拿到RequestManager和ActivityFragmentLifecycle
2、RequestManager如果不為空直接返回,如果為空則透過工廠建立一個RequestManager,並且將ActivityFragmentLifecycle傳入。

getRequestManagerFragment()

1、得到RequestManagerFragment,也就是Fragment
2、將Fragment加入到Activity

RequestManagerFragment

1、Fragment的管理類,繼承Fragment
2、在構造方法裡建立ActivityFragmentLifecycle類
3、在Fragment的onStart()、onStop()、onDestroy()裡呼叫ActivityFragmentLifecycle類裡相應的方法。

ActivityFragmentLifecycle

1、實現Lifecycle介面
2、在Lifecycle的 addListener(@NonNull LifecycleListener listener);裡,將listener一一新增進LifecycleListener的集合,並且呼叫LifecycleListener相應的方法做一些操作,最終的目的是讓每個RequestManager對應一個LifecycleListener

RequestManager

1、實現LifecycleListener介面
2、將RequestManager自身新增到lifecycle方法中,也就是ActivityFragmentLifecycle中,這樣就可以監聽到Fragment的生命週期。

glide還有很多很多的知識點,本篇文章只是介紹glide是如何關聯上Activity的生命週期的,當我們在面試時候,能把實現的過程講出來,我想這是會加分的。看懂原始碼,也就能在 面試過程中針對不同的問題去解答。

最後

要想面試成功進大廠,面試前的準備肯定是要很充分的。

而自己的知識準備得怎麼樣,這直接決定了你能否順利透過一面和二面,所以在面試前來一個知識梳理,看需不需要提升自己的知識儲備是很有必要的。

關於 知識梳理,這裡再分享一下我面試這段時間的複習路線:(以下體系的複習資料是我從各路大佬收集整理好的)

【Android面試技巧】當面試官問你glide的時候,是想問什麼?glide生命週期如何實現?

知識梳理完之後,就需要進行查漏補缺,所以針對這些知識點,我手頭上也準備了不少的電子書和筆記,這些筆記將各個知識點進行了完美的總結:

【Android面試技巧】當面試官問你glide的時候,是想問什麼?glide生命週期如何實現?
Android開發七大模組核心知識筆記

《379頁Android開發面試寶典》

歷時半年,我們整理了這份市面上最全面的安卓面試題解析大全
包含了騰訊、百度、小米、阿里、樂視、美團、58、360、新浪、搜狐等一線網際網路公司面試被問到的題目。熟悉本文中列出的知識點會大大增加透過前兩輪技術面試的機率。

如何使用它?

1.可以透過目錄索引直接翻看需要的知識點,查漏補缺。
2.五角星數表示面試問到的頻率,代表重要推薦指數

【Android面試技巧】當面試官問你glide的時候,是想問什麼?glide生命週期如何實現?

《507頁Android開發相關原始碼解析》

只要是程式設計師,不管是Java還是Android,如果不去閱讀原始碼,只看API文件,那就只是停留於皮毛,這對我們知識體系的建立和完備以及實戰技術的提升都是不利的。

真正最能鍛鍊能力的便是直接去閱讀原始碼,不僅限於閱讀各大系統原始碼,還包括各種優秀的開源庫。

【Android面試技巧】當面試官問你glide的時候,是想問什麼?glide生命週期如何實現?

資料太多,全部展示會影響篇幅,暫時就先列舉這些部分截圖,以上資源均免費分享,以上內容均放在了開源專案: github  中已收錄,大家可以自行獲取。

最後祝大家面試順利,早日找到自己心儀的公司。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2732233/,如需轉載,請註明出處,否則將追究法律責任。

相關文章