Glide框架解析

Glide框架解析

Glide框架基本使用

Glide框架原理

1. with()

Glide为何不能在子线程中with?java

子线程中不会去添加 生命周期管理机制,主线程才会添加一个 空白的Fragment去监听 Activity Fragment的变化。git

每个with()方法重载的代码都很是简单,都是调用调用getRetriever(activity).get(activity),返回一个RequestManager对象。github

getRetriever(...).get(...)作了什么事情?算法

不论传入Activity、FragmentActivity、Fragment最终都会调用supportFragmentGet()方法,而这两个方法最终流程都是一致的就是那就是会向当前的Activity当中添加一个隐藏的Fragment。sql

那么这里为何要添加一个隐藏的Fragment呢?缓存

答:由于Glide须要知道加载的生命周期。很简单的一个道理,若是你在某个Activity上正在加载着一张图片,结果图片还没加载出来,这时候Activity被用户关掉了,那么图片就应该取消加载,但是Glide并不知道Activity的生命周期,怎么办呢? 因而Glide就使用了添加隐藏Fragment的这种小技巧,由于Fragment的生命周期和Activity是同步的,若是Activity被销毁了,Fragment是能够监听到的,这样Glide就能够捕获这个事件并中止图片加载了。安全

既然有了Application,为何不用registerActivityLifecycleCallbacks而是用隐藏的Fragment?markdown

registerActivityLifecycleCallbacks是能够实现,而且个人小伙伴在本身的某些工程中也在使用,可是我的理解是这样的: registerActivityLifecycleCallbacks监控全部的Activity生命周期,然而当你使用Glide加载图片时,并非全部的Activity都会用到Glide加载图片(大多数状况),因此呢,使用registerActivityLifecycleCallbacks存在资源浪费的现象。不只如此,你监控了全部的activity怎么和Glide想要监控的Activity关联到一块去,虽然能够实现,可是这个办法真心不实用,既然Glide给了咱们这么完美的解决方案咱们就要学以至用,之后尽力用到本身的工程中去。网络

2.load()

咱们能够知道.with()方法返回的是GlideRequests对象,GlideRequests是继承自RequestManager(负责管理和请求Glide的请求类),框架

返回 RequestBuilder 对象

3.into()

  1. 获得ImageViewTarget 显示图片的地方
return into(
    // 获得ImageViewTarget 显示图片的地方
    glideContext.buildImageViewTarget(view, transcodeClass));
复制代码
  1. 构建一个请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
复制代码

Glide问题

www.jianshu.com/p/812558735…

1. Glide加载一个100x100的图片,是否会压缩后再加载?放到一个300x300的view上会怎样?

当咱们调整ImageView大小事,Glide会为每一个不一样尺寸的ImageView缓存一张图片,也就是说无论你的这张图片有没有被加载过,只要ImageView的尺寸不同,那么GLide就会从新加载一次,这时候,他会在加载ImageView以前从网络上从新下载,而后再缓存。 举个例子,若是一个页面的ImageView是300 * 300像素,而另外一个页面中的ImageView是100 * 100像素,这时候想要让两个ImageView是同一张图片,那么Glide须要下载两次图片,而且缓存两张图片。

2.三级缓存原理

当 Android 端须要得到数据时好比获取网络中的图片,首先从内存中查找(按键查找),内存中没有的再从磁盘文件或 sqlite 中去查找,若磁盘中也没有才经过网络获取

3.LRUCache 原理

LruCache 是个泛型类,主要原理是:把最近使用的对象用强引用存储在 LinkedHashMap 中,当缓存满时,把最近最少使用的对象从内存中移除,并提供 get/put 方法完成缓存的获取和添加,LruCache 是线程安全的,由于使用了 synchronized 关键字。

当调用 put()方法,将元素加到链表头,若是链表中没有该元素,大小不变,若是有,需调用 trimToSize 方法判断是否超过最大缓存量,trimToSize()方法中有一个 while(true)死循环,若是缓存大小大于最大的缓存值,会不断删除 LinkedHashMap 中队尾的元素,即最少访问的,直到缓存大小小于最大缓存值。

当调用 LruCache 的 get 方法时,LinkedHashMap 会调用recordAccess 方法将此元素加到链表头部

4.Glide 跟Fresco对比

www.jianshu.com/p/1ab5597af…

Glide:

  • 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)
  • 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)
  • 高效处理Bitmap(bitmap的复用和主动回收,减小系统回收压力)
  • 高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不一样,使得内存开销是Picasso的一半)

Fresco:

  • 最大的优点在于5.0如下(最低2.3)的bitmap加载。在5.0如下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)
  • 大大减小OOM(在更底层的Native层对OOM进行处理,图片将再也不占用App的内存)
  • 适用于须要高性能加载大量图片的场景
5.假如让你本身写个图片加载框架,你会考虑哪些问题?

首先,梳理一下必要的图片加载框架的需求:

  • 异步加载:线程池
  • 切换线程:Handler,没有争议吧
  • 缓存:LruCache、DiskLruCache
  • 防止OOM:软引用、LruCache、图片压缩、Bitmap像素存储位置
  • 内存泄露:注意ImageView的正确引用,生命周期管理
  • 列表滑动加载的问题:加载错乱、队满任务过多问题

固然,还有一些不是必要的需求,例如加载动画等。

1.异步加载

线程池,多少个?

缓存通常有三级,内存缓存、硬盘、网络。

因为网络会阻塞,因此读内存和硬盘能够放在一个线程池,网络须要另一个线程池,网络也能够采用Okhttp内置的线程池。

读硬盘和读网络须要放在不一样的线程池中处理,因此用两个线程池比较合适。

2.切换线程

图片异步加载成功,须要在主线程去更新ImageView,

不管是RxJava、EventBus,仍是Glide,只要是想从子线程切换到Android主线程,都离不开Handler。

3.缓存

咱们常说的图片三级缓存:内存缓存、硬盘缓存、网络。

**内存缓存:**通常都是用LruCache

Glide 默认内存缓存用的也是LruCache,只不过并无用Android SDK中的LruCache,不过内部一样是基于LinkHashMap,因此原理是同样的。

为何用LruCache?

LruCache 采用最近最少使用算法,设定一个缓存大小,当缓存达到这个大小以后,会将最老的数据移除,避免图片占用内存过大致使OOM。

4.防止OOM

加载图片很是重要的一点是须要防止OOM,上面的LruCache缓存大小设置,能够有效防止OOM,可是当图片需求比较大,可能须要设置一个比较大的缓存,这样的话发生OOM的几率就提升了,那应该探索其它防止OOM的方法。

5.ImageView 内存泄露

Glide的作法是监听生命周期回调,看 RequestManager 这个类,在Activity/fragment 销毁的时候,取消图片加载任务,细节你们能够本身去看源码。

6.列表加载问题
相关文章
相关标签/搜索