Glide缓存机制源码解读(三)---缓存大小控制及View生命周期感知逻辑

篇章目标要点

Glide是目前最为流行的图片加载框架,内部提供了缓存机制,本文系列目的是记录学习Glide缓存机制要点。缓存最主要的点就是读,写,控制,本文就是围绕这几个方面进行解读。目的是通过向源码学习形成自己的能力进度和思考。目前已经有很多的文章都有撰写相应的学习笔记,部分笔记存在的问题时,所摘取的代码片段未标记代码来源,所以对照源码阅读时,有时找不到位置,本文介绍方法时,会注明相应的类的路径。在第一篇文章中已经介绍了Gilde使用了哪些缓存框架实现的内存缓存和硬盘缓存,完成了下图0.缓存对象构建。第二篇文章中,完整的讲述了Glide加载网络图片的流程和原理(下图1.加载外部图片),加载的数据缓存的流程和原理(下图2.写入缓存),访问外部数据前使用缓存数据的流程(下图3.缓存读取)。本篇文章,重点阐述4.内存缓存空间限制,硬盘缓存空间限制,以及在View的生命周期发生变化时Glide内部的控制机制是怎么样的。
在这里插入图片描述

源码获取

可以在github下载Glide源码进行阅读,通过git工具下载

git clone https://github.com/bumptech/glide.git

内存缓存控制

1.Glide的build方法中会初始化一个BitmapPool进行图片的内存缓存,该对象的创建过程需要设定缓存空间,代码如下

if (bitmapPool == null) {
  //设置Bitmap内存缓存大小,bitmapPool为内存缓存对象
  int size = memorySizeCalculator.getBitmapPoolSize();
  if (size > 0) {
    bitmapPool = new LruBitmapPool(size);
  } else {
    bitmapPool = new BitmapPoolAdapter();
  }
}

2.其内存缓存空间大小是通过MemorySizeCalculator进行计算分配的,分配逻辑如下

/**
 * 内存缓存+硬盘缓存的最大可用空间:低内存时为堆内存的0.33倍,否则为0.4倍
 * 内存缓存:硬盘缓存的所占比例为Android.O以下为4:2,以上为1:2,低内存时为0:2
 * @return
 */
private static int getMaxSize(
    ActivityManager activityManager, float maxSizeMultiplier, float lowMemoryMaxSizeMultiplier) {
  //获取堆内存大小,一般16M
  final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
  //RAM低于1GB为低内存设备
  final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
  //低内存时为堆内存的0.33倍,否则为0.4倍
  return Math.round(
      memoryClassBytes * (isLowMemoryDevice ? lowMemoryMaxSizeMultiplier : maxSizeMultiplier));
}

3.对于自己使用的Android4.4.3设备分配的堆内存是16M,计算下来内存缓存空间上4.3M,硬盘缓存空间为2.1M.
在这里插入图片描述

硬盘缓存控制

硬盘缓存控制对象也是在Glide的Build方法中创建的,其缓存空间的分配逻辑同上述内存分配的代码

/**
 * 设置硬盘缓存的大小
 * 为memoryCache对象赋值为LruResourceCache类型,该类型继承LruCache,基于HashMap在内存中缓存图片
 */
if (memoryCache == null) {
  memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}

View的生命周期感知

Glide需要在with()方法中传入context对象,顺着这条线我们看下其是如何实现生命周期感知的
1.Glide传入上下文参数,返回RequestManager对象

Glide.with(view.getContext()).load(getCurrentList().get(pos).url).placeholder(R.drawable.ic_launcher_foreground).into(imageView);

//返回RequestManager对象
@NonNull
public static RequestManager with(@NonNull Context context) {
  return getRetriever(context).get(context);
}

2.无论上下文是Activity/ FragmentActivity /Fragment/View对象,从源码看内部都是相应的对象可见时才请求

//上下文对象为FragmentActivity时
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  if (Util.isOnBackgroundThread()) {
    //非主线程调用时,不加载
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    FragmentManager fm = activity.getSupportFragmentManager();
    //主线程调用时,当Activity可见时请求数据
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}


//视图可见时执行请求
@NonNull
private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
  SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
  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);
    // This is a bit of hack, we're going to start the RequestManager, but not the
    // corresponding Lifecycle. It's safe to start the RequestManager, but starting the
    // Lifecycle might trigger memory leaks. See b/154405040
    //视图可见时执行请求
    if (isParentVisible) {
      requestManager.onStart();
    }
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

3.我们再看下传入的上下文为View对象时,上下文对象为View时,如该View是在一个Fragment中,那么该Fragment可见时执行请求;如其不在Fragment中,那么Activity可见时执行请求

/**
 * 上下文对象为View时,如该View是在一个Fragment中,那么该Fragment可见时执行请求;
 * 如其不在Fragment中,那么Activity可见时执行请求
 * @param view
 * @return
 */
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull View view) {
  if (Util.isOnBackgroundThread()) {
    return get(view.getContext().getApplicationContext());
  }

  Preconditions.checkNotNull(view);
  Preconditions.checkNotNull(
      view.getContext(), "Unable to obtain a request manager for a view without a Context");
  Activity activity = findActivity(view.getContext());
  // The view might be somewhere else, like a service.
  if (activity == null) {
    return get(view.getContext().getApplicationContext());
  }

  // Support Fragments.
  // Although the user might have non-support Fragments attached to FragmentActivity, searching
  // for non-support Fragments is so expensive pre O and that should be rare enough that we
  // prefer to just fall back to the Activity directly.
  if (activity instanceof FragmentActivity) {
    Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
    return fragment != null ? get(fragment) : get((FragmentActivity) activity);
  }
  //确认View是否存在于某个Fragment中
  // Standard Fragments.
  android.app.Fragment fragment = findFragment(view, activity);
  if (fragment == null) {
    return get(activity);
  }
  return get(fragment);
}

3.返回的RequestManager对象实现了LifecycleListener,具有生命周期感知能力。以下摘取了生命周期关联的onStart()状态时恢复请求任务,onStop()状态时停止请求任务,页面销毁时清除任务。

public class RequestManager
    implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
……
//页面进入onStart()状态时恢复请求动作
/**
 * 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();
}

//页面进入onStop()状态时停止请求动作
/**
 * 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);
  Util.removeCallbacksOnUiThread(addSelfToLifecycle);
  glide.unregisterRequestManager(this);
}

学习心得

了解了内存缓存和硬盘缓存的空间限制的逻辑代码,以及Glide会监听View所在的上下文的生命周期状态实现的生命周期感知。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值