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给了咱们这么完美的解决方案咱们就要学以至用,之后尽力用到本身的工程中去。网络
咱们能够知道.with()
方法返回的是GlideRequests
对象,GlideRequests
是继承自RequestManager
(负责管理和请求Glide的请求类),框架
返回 RequestBuilder 对象
- 获得ImageViewTarget 显示图片的地方
return into(
// 获得ImageViewTarget 显示图片的地方
glideContext.buildImageViewTarget(view, transcodeClass));
复制代码
- 构建一个请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
复制代码
当咱们调整ImageView大小事,Glide会为每一个不一样尺寸的ImageView缓存一张图片,也就是说无论你的这张图片有没有被加载过,只要ImageView的尺寸不同,那么GLide就会从新加载一次,这时候,他会在加载ImageView以前从网络上从新下载,而后再缓存。 举个例子,若是一个页面的ImageView是300 * 300像素,而另外一个页面中的ImageView是100 * 100像素,这时候想要让两个ImageView是同一张图片,那么Glide须要下载两次图片,而且缓存两张图片。
当 Android 端须要得到数据时好比获取网络中的图片,首先从内存中查找(按键查找),内存中没有的再从磁盘文件或
sqlite
中去查找,若磁盘中也没有才经过网络获取
LruCache
是个泛型类,主要原理是:把最近使用的对象用强引用存储在LinkedHashMap
中,当缓存满时,把最近最少使用的对象从内存中移除,并提供 get/put 方法完成缓存的获取和添加,LruCache
是线程安全的,由于使用了 synchronized 关键字。
当调用 put()方法,将元素加到链表头,若是链表中没有该元素,大小不变,若是有,需调用
trimToSize
方法判断是否超过最大缓存量,trimToSize()
方法中有一个 while(true)死循环,若是缓存大小大于最大的缓存值,会不断删除LinkedHashMap
中队尾的元素,即最少访问的,直到缓存大小小于最大缓存值。当调用
LruCache
的 get 方法时,LinkedHashMap
会调用recordAccess
方法将此元素加到链表头部
Glide:
Fresco:
首先,梳理一下必要的图片加载框架的需求:
固然,还有一些不是必要的需求,例如加载动画等。
线程池,多少个?
缓存通常有三级,内存缓存、硬盘、网络。
因为网络会阻塞,因此读内存和硬盘能够放在一个线程池,网络须要另一个线程池,网络也能够采用Okhttp内置的线程池。
读硬盘和读网络须要放在不一样的线程池中处理,因此用两个线程池比较合适。
图片异步加载成功,须要在主线程去更新ImageView,
不管是RxJava、EventBus,仍是Glide,只要是想从子线程切换到Android主线程,都离不开Handler。
咱们常说的图片三级缓存:内存缓存、硬盘缓存、网络。
**内存缓存:**通常都是用
LruCache
Glide 默认内存缓存用的也是LruCache,只不过并无用Android SDK中的LruCache,不过内部一样是基于LinkHashMap,因此原理是同样的。
为何用LruCache?
LruCache 采用最近最少使用算法,设定一个缓存大小,当缓存达到这个大小以后,会将最老的数据移除,避免图片占用内存过大致使OOM。
加载图片很是重要的一点是须要防止OOM,上面的LruCache缓存大小设置,能够有效防止OOM,可是当图片需求比较大,可能须要设置一个比较大的缓存,这样的话发生OOM的几率就提升了,那应该探索其它防止OOM的方法。
Glide的作法是监听生命周期回调,看 RequestManager
这个类,在Activity/fragment 销毁的时候,取消图片加载任务,细节你们能够本身去看源码。