Android--Glide图片加载学习笔记

文章目录


前言

结合Glide讲文,做一篇Glide学习笔记


一、why使用Glide?

        说说为什么使用Glide而不是其他图片加载框架?

  1. 使用简单三步即可,添加依赖-》添加权限-》glide.with(content).load(uri).into(imageView),再高级一点就可以设置图片显示参数等
  2. 生命周期自动绑定,可以根据绑定的Activity或者Fragment生命周期管理图片请求
  3. 高效缓存策略(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),两级内存,两级文件
  4. 支持多种图片格式(GIF、Webp、Jpg)

二、How使用Glide?

1.使用流程

这里简要介绍一下,市面上关于Glide的普通用法甚至进阶用法也很多

  1. 在AndroidManifest.xml文件 添加依赖
  2. 需网络请求,则打开网络请求权限
  3. 加载图片
 glide.with( Content )
      .load(uri)
      .into(imageView

三、Glide关注要点

其中 主要关注的有这么几点

  1. Glide进行图片请求流程
    1. 三级缓存加载图片
    2. 网络获取图片流程
  2. Glide加载图片时,生命周期的绑定与管理
  3. Glide完成网络图片请求后,对数据进行缓存
    1. Glide缓存目的
    2. Glide缓存流程

1. Glide进行图片请求流程

  1. Glide #with 传入绑定组件(content、activity、fragment、view),获取与生命周期绑定的RequsetManager
  2. Glide #load 构造一个RequestBuilder实例,同时往RequestBuilder实例传入需要加载的数据源类型(file、uri、string、drawable、bitmap、resourceId)
  3. Glide #into RequestBuilder中指定图片最终加载位置,并且构建对应的Request、Target
  4. 最后在track方法中,将target加入到追踪队列中(用生命周期自动管理了request请求的开始、暂停和结束等操作),并执行request请求,进行图片请求
  5. 在(4)图片请求,request通过Engine分别尝试从活动缓存、Lru缓存、文件缓存中加载图片,当以上缓存中都不存在对应图片后,会进行网络获取
  6. 网络获取大致可以分成, ModelLoader模型匹配、DataFetcher数据获取,然后再进行解码、图片变换、转换。如果能够进行缓存原始数据,还会将解码的数据进行编码缓存到文件。

2. Glide生命周期绑定

(1) 从Glide.with(context)开始了解生命周期绑定流程

 (1)with()方法 有多个重载,可以传入Context、Activity、Fragment、VIew等

        Glide.with()

public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
  return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
  return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
  return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
  return getRetriever(view.getContext()).get(view);
}

(2)传入后 获得类 RequestManagerRetriever并调用其get方法,具体 get方法如下:

      RequestRetriever.get()

@NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      //获取当前Activity的FragmentManager
      //用于后续将创建的Fragment绑定到activity
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

(3)在 get方法中判断是否在子线程中,在子线程中则调用 get 方法传入 activity.getApplicationContext() ,否则在主线程中:先创建FragmentManager类型的对象fm,再调用supportFragmentGet(),具体代码如下:

      supportFragmentGet()

@NonNull
  private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable Fragment parentHint) {
    //创建无UI的Fragment,并绑定到当前activity
    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,获取fragment的lifecycle,传入requestManager
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

(4) 利用传入的context(也就是with.(context)中的context)和 fm 创建一个无UI的fragment对象 current ,类型为SupportRequestManagerFragment,再利用current创建一个RequestManager类型的requestManager,其中SupportRequestManagerFragment的具体代码如下:

         SupportRequsetFragment()

public class SupportRequestManagerFragment extends Fragment {
  private static final String TAG = "SupportRMFragment";
  private final ActivityFragmentLifecycle lifecycle;

    ...

  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  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();
  }
}

(5) 在SupportRequestManagerFragment中,创建一个ActivityFragmentLifecycle类型的对象lifecycle,但具体进行操作做事的是lifecycle的方法,其中选取onStart方法,代码如下:

        onStart()

void onStart() {
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStart();
    }
  }

(6)在对应生命周期中调用lifecycle的生命周期方法,来通知LifecycleListener,但其实LifecycleListener类的子类就是RequstManager,从而达到了 先前创建的 无UI的Fragment 与 RequsetManager 通信,RequestManager的具体实现代码如下:

        RequestManager

public class RequestManager implements 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 void onStart() {
    resumeRequests();
  }

  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public void onStop() {
    pauseRequests();
  }

  /**
   * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
   * all completed requests.
   */
  @Override
  public void onDestroy() {
    ...
    requestTracker.clearRequests();
  }
}
(7)补充:在(3)中附上的代码 supportFragmentGet中,如果 requestManager ==null,利用 factory.build()方法将 RequestManager生命周期与context绑定
小结:

(1)当我们从 Glide.with(coutext)开始,根据传入的参数,调用对应的重载方法,具体操作为:创建一个RequestManager对象并调用其get方法

(2)在get方法中,判断是否在子线程中

(3)不在子线程中,则创建一个Fragment类型的对象fm, 并调用 supportFragmentGet方法,将 context 和 fm 传入

(4)在supportFragmentGet方法中,创建一个 SupportRequestManagerFragment类型的对象current

        1)在对象current生命周期方法中,实际调用的是lifecycle的生命周期方法,而在lifecycle的生命周期方法中,实现与lifecycleListener的通信,而lifecycleListener的子类

        就是RequestManager

        2)再利用 current.getRequesrManager方法创建一个RequstManager对象

        3)再判断RequstManager对象是否为空,若为 空,则传入 context,创建 glide对象,使用factory.build绑定current,从而实现生命周期绑定

(2)生命周期时长

虽然with方法有多个重载,但是其实可以根据glide.with(context)传入的参数是否为Application类型参数,分为两种情况

  1. 传入Application Context或者在 get方法中判断在子线程中使用 :调用getApplicationManager(context);  这样 Glide的生命周期就和应用程序一样,因为相比于 传入Activity、Fragment对象,因为获取的是ApplicationLifecycle,不创建Fragment,所以只会调用onStart方法
  2. 其他情况,比如传入Activity、Fragment等:调用 supportFragmentGet方法, Glide就会在生命周期不同的方法中对请求做不同处理,

(3)总结

  1. Glide关联生命周期大致分为两部分
    1. 与组件绑定(通过创建一个无UI的Fragment对象 current)
    2. 传递生命周期(RequstManager与Fragment之间通过LifeCycle、LifecycleListener接口回调实现)
  2. Glide.with()方法,使用glide.with(getApplicationContext()),则生命周期与应用程序一样,传入Activitiy或Fragment ,才可以绑定关联组件生命周期
  3. 在UI线程中调用Glide、子线程中使用Glide和使用 ApplicationContext一样

3. Glide缓存管理

Glide缓存 分为两部分:内存缓存(弱引用(weakReference)+Lrucache)+硬盘缓存(DiskLrucache,与Lrucache差不多),所以常说三级缓存是 weakReference --> Lrucache --> DiskLrucache

(1)引入缓存目的

  • 减少流量消耗,加快响应速度
  • 使用缓存可以更加高效的加载Bitmap,减少卡顿

(2)缓存流程

取顺序:弱引用 -->Lrucache -->DiskLrucache -->网络

写顺序:DiskLrucache -->弱引用,当计数器为0 的时候,再放到Lrucache中

(3)缓存原理

  1. 弱引用
    1. 底层数据结构:HashMap ,key是缓存的key,由uri,width,height等参数组成;value是图片资源对象的弱引用形式
  2. LruCache
    1. 底层数据结构:linkedHashMap,LRU Least Recently Used的缩写,最近最少使用置换算法,而LinkHashMap链表则是把最近使用过的文件插到列表头部,未使用的图片放到尾部
  3. 存取原理
    1. ​​​​​​​在内存缓存中由一个概念叫图片引用计数器,是在EngineResource中定义一个acquired变量用来记录图片被引用的次数,调用acquire()方法会让变量加1,调用release()方法会让变量减1
  4. 获得图片资源
    1. ​​​​​​​​​​​​​​

      首先从弱引用取缓存,拿到则计数+1;没拿到则从Lrucache中拿缓存,拿则计数+1,同时把图片从Lrucache缓存转移到弱引用缓存中;没拿到的话,九通过EngineJob开启线程池取加载图片,拿到的话计数+1,并把图片放到弱引用缓存中

  5. 存数据
    1. ​​​​​​​​​​​​​​在加载图片之后,可以把图片数据缓存下来,通过EngineJob开启线程池取加载图片,取到数据后再回调主线程,把图片存到弱引用中,当图片不再使用时,比如暂停请求或者加载完毕或者清除资源时,就会将其从弱引用中转移到LruCache中
  6. 引入弱引用作用
    1. 提高效率

(4)手写Lrucache

待续...

(5)磁盘缓存

1. 如果再内存缓存(弱引用+Lrucache)中没拿到数据,就通过EngineJob开启线程池去加载图片,通过 EngineJob内部维护线程池,用来管理资源加载,当资源加载完成后通知回调;DecodeJob是线程池中的一个任务

2. 磁盘缓存是通过DiskLrucache来管理,根据缓存策略分为两种类型的图片:DATA(原始图片)和 RESOURCE(转换后图片)。

3. 磁盘缓存依次通过

1. ResourceCacheGenerator(获取转换后的缓存数据)

2. SourceCacheGenerator(获取未经转换的原始缓存数据)

3. DataCacheGenerator(通过网络获取图片数据,再按照不同缓存策略去缓存不同图片到磁盘上)来获取缓存数据


总结

对Glide生命周期进行学习总结,并了解Glide加载缓存流程

Glide中Lrucache的手写后续补上

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值