Glide V4 源碼淺析(下)-- 細(xì)節(jié)分析功能模塊的實(shí)現(xiàn)

在上篇我們主要分析了圖片加載的主流程,但是Glide框架的某些優(yōu)勢我們還未進(jìn)行分析,本篇就針對Glide的這些優(yōu)勢時如何實(shí)現(xiàn)的進(jìn)行分析。

細(xì)節(jié)分析實(shí)現(xiàn)

1 Glide如何實(shí)現(xiàn)生命周期管理

我們在上篇提到在Glide.with()時,Glide會對傳入的參數(shù)進(jìn)行封裝處理,我們繼續(xù)以Activity為例。

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      //獲取FragmentManager后將activity和fm作為參數(shù)傳入fragmentGet方法
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  
  @NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //初始化一個RequestManagerFragment
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      Glide glide = Glide.get(context);
      //創(chuàng)建requestManager時將RequestManagerFragment的GlideLifecycle作為參數(shù)傳遞了進(jìn)去
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  
    private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    //判斷釋放存在已生成的RequestManagerFragment,如果已生成則直接返回,否則直接進(jìn)行初始化
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //初始化一個RequestManagerFragment
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        //根據(jù)isParentVisible(即傳入activity的顯示狀態(tài))確定是否要直接調(diào)用GlideLifecycle的onStart()方法
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

從上文可以看到Glide在生成requestManager時首先生成了一個RequestManagerFragment,而這個RequestManagerFragment是一個無視圖的Fragment,用于啟動,停止和管理Glide請求。在這個Fragment中初始化了一個ActivityFragmentLifecycle。它便是Glide進(jìn)行生命周期管理的一個關(guān)鍵。

public class RequestManagerFragment extends Fragment {
  private final ActivityFragmentLifecycle lifecycle;
  //省略部分代碼
  ......
  public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }
  //省略部分代碼
  ......
  
}

而這個ActivityFragmentLifecycle就是是用于追蹤Activity或者fragment的生命周期的。代碼如下

class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;
  @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();
    }
  }
}

由代碼可以看出,這個類是一個lifecycleListener的管理類,用于在狀態(tài)改變時通知這些lifecycleListeners。而這個類會在RequestManager.build()時作為參數(shù)傳遞進(jìn)去

  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;

    //在這里RequestManager,將自身作為callback傳入
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }
  
  @Override
  public void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  @Override
  public void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

  @Override
  public 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);
  }

可以看到這樣一來,當(dāng)ActivityFragmentLifecycle狀態(tài)改變時就會通知到RequestManager。而RequestManager便會在相應(yīng)的回調(diào)方法中來控制targetTracker和requestTracker。而這兩個類我們在上篇中以及提到了,分別用來控制viewTarget和requests,而這兩者又是對要顯示的view和相應(yīng)的加載請求的封裝。而最后在我們getRequestManagerFragment()方法中生成的RequestManagerFragment,會在生命周期發(fā)生變化時通知ActivityFragmentLifecycle。

  @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();
  }

這樣以來便可以實(shí)現(xiàn)通過生命周期來控制圖片加載的功能了。

2 Glide如何實(shí)現(xiàn)緩存

Glide的緩存也是一個經(jīng)常被人稱道的地方,我們一般都知道內(nèi)存-文件-網(wǎng)絡(luò)三級緩存,那么Glide又是如何實(shí)現(xiàn)緩存的呢?

2.1 內(nèi)存緩存

在上文提到過Glide調(diào)用Engine的load()方法時會進(jìn)行內(nèi)存緩存的讀取

public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    //嘗試獲取ActiveResources
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    //嘗試獲取CacheResources
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    
    //省略部分代碼
    .....
  }

首先獲取第一階段的內(nèi)存緩存ActiveResources

  @Nullable
  private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    //不允許讀取緩存直接返回null
    if (!isMemoryCacheable) {
      return null;
    }
    //根據(jù)key從activeResources中獲取對應(yīng)的EngineResource
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }
    return active;
  }

這里我們可以看到讀取緩存資源時時會從activeResources中查找,而activeResources是一個使用HashMap和WeakReference對EngineResource進(jìn)行保存的管理類。它的代碼邏輯如下:

final class ActiveResources {
  private static final int MSG_CLEAN_REF = 1;

  private final boolean isActiveResourceRetentionAllowed;
  private final Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() {
    @Override
    public boolean handleMessage(Message msg) {
      if (msg.what == MSG_CLEAN_REF) {
        cleanupActiveReference((ResourceWeakReference) msg.obj);
        return true;
      }
      return false;
    }
  });
  //用于保存EngineResource的HashMap
  @VisibleForTesting
  final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();

  private ResourceListener listener;

  @Nullable
  private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;
  @Nullable
  private Thread cleanReferenceQueueThread;
  private volatile boolean isShutdown;
  @Nullable
  private volatile DequeuedResourceCallback cb;

  ActiveResources(boolean isActiveResourceRetentionAllowed) {
    this.isActiveResourceRetentionAllowed = isActiveResourceRetentionAllowed;
  }

  void setListener(ResourceListener listener) {
    this.listener = listener;
  }

  //添加對應(yīng)鍵值對
  void activate(Key key, EngineResource<?> resource) {
    ResourceWeakReference toPut =
        new ResourceWeakReference(
            key,
            resource,
            getReferenceQueue(),
            isActiveResourceRetentionAllowed);

    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
      removed.reset();
    }
  }

  //移除對應(yīng)鍵值對
  void deactivate(Key key) {
    ResourceWeakReference removed = activeEngineResources.remove(key);
    if (removed != null) {
      removed.reset();
    }
  }

  //get方法
  @Nullable
  EngineResource<?> get(Key key) {
    //先從HashMap中獲取ResourceWeakReference
    ResourceWeakReference activeRef = activeEngineResources.get(key);
    if (activeRef == null) {
      return null;
    }
    //再從ResourceWeakReference中獲取對應(yīng)的EngineResource
    EngineResource<?> active = activeRef.get();
    //當(dāng)發(fā)現(xiàn)此弱引用不存在時進(jìn)去清除邏輯
    if (active == null) {
      cleanupActiveReference(activeRef);
    }
    return active;
  }

  //清除對應(yīng)的弱引用
  @SuppressWarnings("WeakerAccess")
  @Synthetic void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
    Util.assertMainThread();
    //hashmap中移除此索引
    activeEngineResources.remove(ref.key);

    //判斷該ResourceWeakReference對應(yīng)的資源文件是否還存在
    if (!ref.isCacheable || ref.resource == null) {
      return;
    }
    //創(chuàng)建新的EngineResource
    EngineResource<?> newResource =
        new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
    newResource.setResourceListener(ref.key, listener);
    //通知監(jiān)聽器
    listener.onResourceReleased(ref.key, newResource);
  }

  private ReferenceQueue<EngineResource<?>> getReferenceQueue() {
    if (resourceReferenceQueue == null) {
      resourceReferenceQueue = new ReferenceQueue<>();
      cleanReferenceQueueThread = new Thread(new Runnable() {
        @SuppressWarnings("InfiniteLoopStatement")
        @Override
        public void run() {
          Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
          cleanReferenceQueue();
        }
      }, "glide-active-resources");
      cleanReferenceQueueThread.start();
    }
    return resourceReferenceQueue;
  }

  //清理資源引用隊(duì)列
  @SuppressWarnings("WeakerAccess")
  @Synthetic void cleanReferenceQueue() {
    while (!isShutdown) {
      try {
        ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
        mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget();

        // This section for testing only.
        DequeuedResourceCallback current = cb;
        if (current != null) {
          current.onResourceDequeued();
        }
        // End for testing only.
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }
  }

  @VisibleForTesting
  void setDequeuedResourceCallback(DequeuedResourceCallback cb) {
    this.cb = cb;
  }

  @VisibleForTesting
  interface DequeuedResourceCallback {
    void onResourceDequeued();
  }

  //停止cleanReferenceQueueThread線程,中斷操作
  @VisibleForTesting
  void shutdown() {
    isShutdown = true;
    if (cleanReferenceQueueThread == null) {
      return;
    }

    cleanReferenceQueueThread.interrupt();
    try {
      cleanReferenceQueueThread.join(TimeUnit.SECONDS.toMillis(5));
      if (cleanReferenceQueueThread.isAlive()) {
        throw new RuntimeException("Failed to join in time");
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  //弱引用對象,但是對于資源文件Resource卻是直接用強(qiáng)引用進(jìn)行保存的
  @VisibleForTesting
  static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
    @SuppressWarnings("WeakerAccess") @Synthetic final Key key;
    @SuppressWarnings("WeakerAccess") @Synthetic final boolean isCacheable;

    @Nullable @SuppressWarnings("WeakerAccess") @Synthetic Resource<?> resource;

    @Synthetic
    @SuppressWarnings("WeakerAccess")
    ResourceWeakReference(
        @NonNull Key key,
        @NonNull EngineResource<?> referent,
        @NonNull ReferenceQueue<? super EngineResource<?>> queue,
        boolean isActiveResourceRetentionAllowed) {
      super(referent, queue);
      this.key = Preconditions.checkNotNull(key);
      this.resource =
          referent.isCacheable() && isActiveResourceRetentionAllowed
              ? Preconditions.checkNotNull(referent.getResource()) : null;
      isCacheable = referent.isCacheable();
    }

    //清除自身
    void reset() {
      resource = null;
      clear();
    }
  }
}

從上文代碼中可以看出,當(dāng)我們通過ActiveResources的activate方法加入一個新的鍵值對時,會創(chuàng)建一個ResourceWeakReference用于保存key和resource,而同時會調(diào)用getReferenceQueue()方法,在這個方法中會啟動一個后臺線程cleanReferenceQueueThread,在此線程中會進(jìn)入一個循環(huán),當(dāng)弱引用被回收時,就會將通知handle,調(diào)用cleanupActiveReference方法,而此時由于ResourceWeakReference中保存key和resource是通過強(qiáng)引用的方式進(jìn)行保存的,所以可以取出對應(yīng)的resource,創(chuàng)建新的EngineResource,并調(diào)用listener.onResourceReleased()方法,ActiveResources的listener就是Engine,因此我們可以看到Engine的onResourceReleased方法

  @Override
  public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    Util.assertMainThread();
    //清除對應(yīng)的key,并解除對資源的強(qiáng)引用
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
      //將傳入的key、resource放入新的cache中
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }

此時的cache為LruResourceCache,是在Glide創(chuàng)建過程中進(jìn)行初始化的

  Glide build(@NonNull Context context) {
    //省略部分代碼
    ......
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
    //省略部分代碼
    ......
  }

LruResourceCache用于在ActiveResources未命中時進(jìn)行緩存查找,即上文中調(diào)用到的loadFromCache()方法

  private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    //獲取CacheResource
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      //引用加一
      cached.acquire();
      //將其添加到ActiveResources
      activeResources.activate(key, cached);
    }
    return cached;
  }
  
  
  private EngineResource<?> getEngineResourceFromCache(Key key) {
    //獲取資源文件,并在cache中移除
    Resource<?> cached = cache.remove(key);

    final EngineResource<?> result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource<?>) cached;
    } else {
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
    }
    return result;
  }

LruResourceCache本身是LruCache的子類,并且實(shí)現(xiàn)MemoryCache接口(用于添加和移除資源),其中LRU實(shí)現(xiàn)也是通過LinkedHashMap來實(shí)現(xiàn)的。
至此Glide的內(nèi)存緩存已經(jīng)結(jié)束了,可以看到Glide設(shè)計了兩層緩存,分別是ActiveResources和LruResourceCache,用弱引用和Lru來進(jìn)行資源的保存,并且它們之間有相互添加的過程。

2.2 文件緩存

上篇中提到了,當(dāng)一個任務(wù)未能從內(nèi)存緩存中獲取相應(yīng)的資源時,會啟動DecodeJob來執(zhí)行加載任務(wù),而在第一次啟動DecodeJob時runReason為INITIALIZE,此時會嘗試從文件內(nèi)存中獲取對應(yīng)資源

  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE://初始
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE://從CACHE跳轉(zhuǎn)到SOURCE
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();//DECODE_DATA
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

其中主要的標(biāo)識位為Stage,Stage有6種狀態(tài)

  private enum Stage {
    //初始狀態(tài)
    INITIALIZE,
    //裁剪圖緩存
    RESOURCE_CACHE,
    //原圖緩存
    DATA_CACHE,
    //原圖地址
    SOURCE,
    //解析
    ENCODE,
    //完成
    FINISHED,
  }
  
  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        //判斷是否支持使用裁剪圖緩存若支持則返回狀態(tài)為RESOURCE_CACHE,否則接著進(jìn)行狀態(tài)查詢
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        //判斷是否支持使用原圖緩存若支持則返回狀態(tài)為DATA_CACHE,否則接著進(jìn)行狀態(tài)查詢
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        //如果該任務(wù)只允許從緩存中讀取,則返回狀態(tài)為FINISHED,否則就是SOURCE
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

當(dāng)確認(rèn)了狀態(tài)后會根據(jù)stage獲取對應(yīng)的currentGenerator,

  private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

而各種Generator中會調(diào)用對應(yīng)的緩存信息來獲取對應(yīng)的資源,從而完成文件緩存。

結(jié)

至此我們分析了在上篇中未提到的部分功能的實(shí)現(xiàn)細(xì)節(jié),由于Glide是一個十分完善的圖片加載庫,因此還有許多功能并未進(jìn)行分析。
本篇文章是個人學(xué)習(xí)的總結(jié),本人能力有限,如果有錯誤歡迎斧正,謝謝。

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

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

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