Glide实现原理解析

一.Glide缓存机制

Glide采取的多级缓存机制,能够较为友好地实现图片、动图的加载。其主要有 内存缓存+磁盘缓存 ,当然他们的作用也有不同,其中内存缓存主要用于防止将重复的图读入内存中,磁盘缓存则用于防止从网络或者其他地方将重复下载和数据读取。

默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:

  1. 活动资源 (Active Resources)
  2. 内存缓存 (Memory Cache)
  3. 资源类型(Resource Disk Cache)
  4. 原始数据 (Data Disk Cache)

活动资源:如果当前对应的图片资源正在使用,则这个图片会被Glide放入活动缓存。
内存缓存:如果图片最近被加载过,并且当前没有使用这个图片,则会被放入内存中
资源类型: 被解码后的图片写入磁盘文件中,解码的过程可能修改了图片的参数(如:inSampleSize。inPreferredConfig)
原始数据: 图片原始数据在磁盘中的缓存(从网络、文件中直接获得的原始数据)

在调用into之后,Glide会首先从Active Resources查找当前是否有对应的活跃图片,没有则查找内存缓存,没有则查找资源类型,没有则查找数据来源。

1.活动资源

活动资源中是一个”引用计数"的图片资源的弱引用集合。使用一个 Map<Key, WeakReference<EngineResource<?>>> 来存储的。

此外还有一个引用队列ReferenceQueue<EngineResource<?>> resourceReferenceQueue;每当向 activeResource 中添加一个 WeakReference 对象时都会将 resourceReferenceQueue 和这个 WeakReference 关联起来,用来跟踪这个 WeakReference 的 gc,一旦这个弱引用被 gc 掉,就会将它从 activeResource 中移除。

ReferenceQueue 具体是在何时去判断 WeakReference 是否被 gc 了呢?
老版本调用 MessageQueue#addIdleHandler 添加一个 MessageQueue.IdleHandler 对象,Handler 会在线程空闲时调用这个方法。
新版本开启一个线程,使用handler发送消息判断

当需要加载某张图片能够从内存缓存中获得的时候,在图片加载时主动将对应图片从内存缓存中移除,加入到活动资源中。
这样也可以避免因为达到内存缓存最大值或者系统内存压力导致的内存缓存清理,从而释放掉活动资源中的图片(recycle)。

因为同一张图片可能在多个地方被同时使用,每一次使用都会将引用计数+1,而当引用计数为0时候,则表示这个图片没有被使用也就是没有强引用了。这样则会将图片从活动资源中移除,并加入内存缓存。

2.内存缓存

内存缓存默认使用LRU(缓存淘汰算法/最近最少使用算法),当资源从活动资源移除的时候,会加入此缓存。使用图片的时候会主动从此缓存移除,加入活动资源。LRU在Android support-v4中提供了LruCache工具类。

3.磁盘缓存

资源类型缓存的是经过解码后的图片,如果再使用就不需要再去进行解码配置(BitmapFactory.Options),加快获得图片速度。比如原图是一个100x100的ARGB_8888图片,在首次使用的时候需要的是50x50的RGB_565图片,那么Resource将50x50 RGB_565缓存下来,再次使用此图片的时候就可以从 Resource 获得。不需要去计算inSampleSize(缩放因子)。
原始数据缓存的则是图像原始数据。


Bitmap复用池

如果缓存都不存在,那么会从源地址获得图片(网络/文件)。而在解析图片的时候会需要可以获得BitmapPool(复用池),达到复用的效果。复用并不能减少程序正在使用的内存大小。Bitmap复用,解决的是减少频繁申请内存带来的性能(抖动、碎片)问题。

BitmapPool是Glide中的Bitmap复用池,同样适用LRU来进行管理。在每次解析一张图片为Bitmap的时候(磁盘缓存、网络/文件)会从其BitmapPool中查找一个可被复用的Bitmap。当一个Bitmap从内存缓存 被动 的被移除(内存紧张、达到maxSize)的时候并不会被recycle。而是加入这个BitmapPool,只有从这个BitmapPool 被动的被移除的时候,Bitmap的内存才会真正被recycle释放。

Bitmap复用方式为在解析的时候设置Options的inBitmap属性。

  1. Bitmap的inMutable需要为true。
  2. Android 4.4及以上只需要被复用的Bitmap的内存必须大于等于需要新获得Bitmap的内存,则允许复用此Bitmap。
  3. 4.4以下(3.0以上)则被复用的Bitmap与使用复用的Bitmap必须宽、高相等并且使用复用的Bitmap解码时设置的inSampleSize为1,才允许复用。

二.Glide生命周期管理

Glide在Glide.with(context)中就实现了生命周期管理,with根据传入的参数有不同的实现。

  //传入一个Context
  public static RequestManager with(@NonNull Context context)
  //传入一个activity
  public static RequestManager with(@NonNull Activity activity)
  //传入一个FragmentActivity
  public static RequestManager with(@NonNull FragmentActivity activity)
  //传入一个Fragment
  public static RequestManager with(@NonNull Fragment fragment)
  //传入一个View
  public static RequestManager with(@NonNull View view)

虽然有这么多类型,但其实可以分为两类的。

  • 传入一个ApplicationContext,Glide的生命周期就相当于绑定了整个应用,只要应用不退出,任何时候都能够加载,也可以理解为不对Glide生命周期进行管理。

  • 传入activity、FragmentActivity 、Fragment 及View ,这样就会创建一个看不见的fragment,Glide的生命周期就随着该Fragment的变化而变化。

当传入参数为ApplicationContext时,代码实现如下。

  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }
  //由于传入参数是ApplicationContext,所以最终调用getApplicationManager方法。
  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) {
        //判断context类型是不是FragmentActivity
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        //判断context类型是不是Activity
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        //判断context类型是不是ContextWrapper
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    //context类型属于ApplicationContext
    return getApplicationManager(context);
  }

由于传入参数是ApplicationContext,所以最终调用getApplicationManager方法。

  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    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;
  }

这里就直接创建一个ApplicationLifecycle来管理生命周期,但ApplicationLifecycle并不受控制,所以就无法对Glide生命周期进行管理。
 以传入参数类型为Activity为例,代码实现如下。

  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }
  public RequestManager get(@NonNull Activity activity) {
    //如果在子线程,则不对Glide生命周期就那些管理
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      //拿到FragmentManager对象
      android.app.FragmentManager fm = activity.getFragmentManager();
      //获取fragment对象,并返回一个RequestManager 对象
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

如果当前是在子线程,则不需要对Glide生命周期进行管理,否则将通过fragmentGet方法创建一个fragment。

  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //创建一个fragment对象
    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 = Glide.get(context);
      //创建一个RequestManager对象
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

在该方法中,通过getRequestManagerFragment来获得一个Fragment对象。然后拿到该Fragment对应的RequestManager 对象,如果该对象为null则创建一个RequestManager对象并将fragment中的ActivityFragmentLifecycle对象传递给RequestManager。先来看getRequestManagerFragment方法的实现。

  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //查找tag为FRAGMENT_TAG的fragment
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //从HashMap中取出fm
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //创建fragment对象
        current = new RequestManagerFragment();
        //当fragment嵌套fragment时才会使用,否则parentHint是null
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          //开始执行请求
          current.getGlideLifecycle().onStart();
        }
        //将fm添加到HashMap中,防止fragment的重复创建
        pendingRequestManagerFragments.put(fm, current);
        //添加fragment
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //从HashMap集合从移除fm
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

从fm中去查找tag为FRAGMENT_TAG的fragment是否存在,如果不存在就从pendingRequestManagerFragments这个HashMap中去取,如果没有就创建一个fragment,添加到pendingRequestManagerFragments并且将该fragment绑定到activity,绑定成功后则从pendingRequestManagerFragments移除fragment。这里的pendingRequestManagerFragments主要是防止fragment重复创建(Glide生命周期管理),因为每个activity必须对应一个唯一的fragment。来看一下这个fragment的实现RequestManagerFragment。

public class RequestManagerFragment extends Fragment {
  private final ActivityFragmentLifecycle lifecycle;
  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
  ...
  @NonNull
  ActivityFragmentLifecycle getGlideLifecycle() {
    return 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();
  }
  ...
}

再回到fragmentGet方法,fragment创建成功后,在创建RequestManager时会传入fragment中的ActivityFragmentLifecycle,再来看RequestManager的实现。

public class RequestManager implements LifecycleListener,
    ModelTypes<RequestBuilder<Drawable>> {
  private final Runnable addSelfToLifecycle = new Runnable() {
    @Override
    public void run() {
      lifecycle.addListener(RequestManager.this);
    }
  };
  public RequestManager(
      @NonNull Glide glide, @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
    this(
        glide,
        lifecycle,
        treeNode,
        new RequestTracker(),
        glide.getConnectivityMonitorFactory(),
        context);
  }

  // Our usage is safe here.
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  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()) {
      //当在子线程时通过Handler将当前对象注册到ActivityFragmentLifecycle
      mainHandler.post(addSelfToLifecycle);
    } else {
      //将当前对象注册到ActivityFragmentLifecycle
      lifecycle.addListener(this);
    }
    //网络变化监听
    lifecycle.addListener(connectivityMonitor);
    ...
  }
  //开始加载
  @Override
  public synchronized void onStart() {
    resumeRequests();
    //如果有动画则开始动画
    targetTracker.onStart();
  }
  //停止加载
  @Override
  public synchronized void onStop() {
    pauseRequests();
    //如果有动画则动画停止
    targetTracker.onStop();
  }
  //销毁
  @Override
  public synchronized void onDestroy() {
    //如果有动画则动画结束并销毁
    targetTracker.onDestroy();
    ...
  }
  //开始请求数据
  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
 ...
}

可以看见在RequestManager的构造函数将RequestManager注册到ActivityFragmentLifecycle中,再来看看ActivityFragmentLifecycle的实现。

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);
  }
  //每个RequestManager对应一个LifecycleListener
  void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStart();
    }
  }
  //每个RequestManager对应一个LifecycleListener
  void onStop() {
    isStarted = false;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStop();
    }
  }
  //每个RequestManager对应一个LifecycleListener
  void onDestroy() {
    isDestroyed = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onDestroy();
    }
  }
}

由于ActivityFragmentLifecycle对象是在fragment中创建并且它的onStart、onStop、onDestory方法与fragment一一对应,这样就将RequestManager的生命周期就与fragment关联起来了,也就与当前activity关联起来。总体流程如下:

在这里插入图片描述

当fragment生命周期发生变化时,通过ActivityFragmentLifecycle将变化告诉给RequestManager与DefaultConnectivityMonitor。而RequestManager又将此变化告诉给ImageViewTarget。
 至于传入参数为其他类型的实现基本上与activity的类似,就不在叙述。

发布了82 篇原创文章 · 获赞 155 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/hxl517116279/article/details/99639520