首頁>技術>

去面試的時候,我們也經常被問到這樣的問題:專案用什麼圖片載入框架?為什麼選擇這個框架?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(),相關的原始碼已經在以上講解中貼出。

fragmentGet()呼叫getRequestManagerFragment()得到RequestManagerFragment,也就是Fragment的管理類。 從RequestManagerFragment拿到RequestManager和ActivityFragmentLifecycleRequestManager如果不為空直接返回,如果為空則通過工廠建立一個RequestManager,並且將ActivityFragmentLifecycle傳入。getRequestManagerFragment()得到RequestManagerFragment,也就是Fragment將Fragment加入到ActivityRequestManagerFragmentFragment的管理類,繼承Fragment在構造方法裡建立ActivityFragmentLifecycle類在Fragment的onStart()、onStop()、onDestroy()裡呼叫ActivityFragmentLifecycle類裡相應的方法。ActivityFragmentLifecycle實現Lifecycle介面在Lifecycle的addListener(@NonNull LifecycleListener listener);裡,將listener一一新增進LifecycleListener的集合,並且呼叫LifecycleListener相應的方法做一些操作,最終的目的是讓每個RequestManager對應一個LifecycleListenerRequestManager實現LifecycleListener介面將RequestManager自身新增到lifecycle方法中,也就是ActivityFragmentLifecycle中,這樣就可以監聽到Fragment的生命週期。

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

文末

今天關於面試的分享就到這裡,還是那句話,有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。

還有 高階架構技術進階腦圖、Android開發面試專題資料,高階進階架構資料 幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習。

【Android核心高階技術PDF文件,BAT大廠面試真題解析】

【Android進階學習視訊】、【全套Android面試祕籍PDF】、【Android開發核心知識點筆記】可以 私信我【安卓】免費獲取!

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 告別“馬賽克”!演算法來拯救畫質,這個專案在GitHub已斬獲1k星