推荐一篇关于三级缓存的文章
三级缓存(MemoryCache,DiskCache,NetCache)
浅析LRUCache原理(Android)
. LruCache部分源码解析
LruCache 利用 LinkedHashMap 的一个特性(accessOrder=true 基于访问顺序)再加上对 LinkedHashMap 的数据操作上锁实现的缓存策略。
LRU全称为Least Recently Used,即最近最少使用。
- 首先设置了内部 LinkedHashMap 构造参数 accessOrder=true, 实现了数据排序按照访问顺序。
LruCache类在调用get(K key) 方法时,都会调用LinkedHashMap.get(Object key) 。 - 如上述设置了 accessOrder=true 后,调用LinkedHashMap.get(Object key) 都会通过LinkedHashMap的afterNodeAccess()方法将数据移到队尾。
- 由于最新访问的数据在尾部,在 put 和 trimToSize 的方法执行下,如果发生数据移除,会优先移除掉头部数据,trimToSize()方法不断地删除LinkedHashMap中队首的元素,即近期最少访问的,直到缓存大小小于最大值。
Glide
Glide.with(this).load(url).into(imageView);
三步走:先with(),再load(),最后into()
with()方法
是Glide类中的一组静态方法,
with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。每一个with()方法重载的代码都非常简单,都是先调用RequestManagerRetriever的静态get()方法得到一个
RequestManagerRetriever对象,这个静态get()方法就是一个单例实现,
然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。
public RequestManager get(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) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
--------------------------------------------------------------------------------------
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}
get方法首先会判断传入的Context的类型,如果传入的Context类型是Application或者是在子线程加载的图片,这会通过getApplicationManager方法单例形式创建一个RequestManager对象。
否则会调用fragmentGet方法,传入Context对象和FragmentManager对象
这几个重载方法最终都是调用RequestManagerRetriever.get()方法获取RequestManagerRetriever对象,然后通过这个对象获取RequestManager对象
总结
width方法最终目的都是通过RequestManagerRetriever对象的get方法获取RequestManager对象,传入参数主要分Application类型和非Application类型
如果with方法传入的是Application,会通过调用getApplicationManager()来获取一个RequestManager对象,不需要处理生命周期,因为Application对象的生命周期就是应用程序的生命周期
如果with方法传入的不是Application类型,最终流程都是一样,那就是会向当前的Activity当中添加一个隐藏的Fragment,app包下的fragment会调用fragmentGet方法创建隐藏fragment,v4包下的fragment会调用supportFragmentGet方法创建fragment,都会返回RequestManager对象,创建隐藏fragment的目的是Glide需要知道加载的生命周期,可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理,调用getApplicationManager()来获取RequestManager对象
SupportRequestManagerFragment类里面 构造方法中创建了一个ActivityFragmentLifecycle对象,这个对象就是监听fragment生命周期的,从fragment的生命周期方法中可以很明确看出来。
load()方法
参数类型:String,File,byte[],URL,图片资源ID,Uri,我这里只看参数类型为String类型的,这些方法都会返回DrawableTypeRequest对象。
load内部调用了fromString方法,fromString方法调用了loadGeneric方法,
loadGeneric()方法也没几行代码,这里分别调用了Glide.buildStreamModelLoader()方法和Glide.buildFileDescriptorModelLoader()方法来获得ModelLoader对象。
ModelLoader对象是用于加载图片的,而我们给load()方法传入不同类型的参数,这里也会得到不同的ModelLoader对象,最后返回一个DrawableTypeRequest对象。
DrawableTypeRequest的父类是DrawableRequestBuilder,
DrawableRequestBuilder中有很多个方法,这些方法其实就是Glide绝大多数的API了。里面有不少我们在上篇文章中已经用过了,比如说placeholder()方法、error()方法、diskCacheStrategy()方法、override()方法等,都是在DrawableRequestBuilder 类里面。提供了glide加载图片过程的很多方法
public class DrawableRequestBuilder
extends GenericRequestBuilder
implements BitmapOptions, DrawableOptions {
DrawableRequestBuilder(Context context, Class modelClass,
LoadProvider loadProvider, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle) {
super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
// Default to animating.
crossFade();
}
//图片的一种显示格式
@SuppressWarnings("unchecked")
public DrawableRequestBuilder centerCrop() {
return transform(glide.getDrawableCenterCrop());
}
//图片的一种显示格式
@SuppressWarnings("unchecked")
public DrawableRequestBuilder fitCenter() {
return transform(glide.getDrawableFitCenter());
}
//图片显示设置渐变时间
public DrawableRequestBuilder crossFade(int duration) {
super.animate(new DrawableCrossFadeFactory(duration));
return this;
}
//磁盘缓存策略
@Override
public DrawableRequestBuilder diskCacheStrategy(DiskCacheStrategy strategy) {
super.diskCacheStrategy(strategy);
return this;
}
//是否跳过内存缓存
@Override
public DrawableRequestBuilder skipMemoryCache(boolean skip) {
super.skipMemoryCache(skip);
return this;
}
//设置图片尺寸
@Override
public DrawableRequestBuilder override(int width, int height) {
super.override(width, height);
return this;
}
//设置图片加载优先级
@Override
public DrawableRequestBuilder priority(Priority priority) {
super.priority(priority);
return this;
}
}
GenericRequestBuilder类:DrawableRequestBuilder的父类,这里面提供了绝大部分glide加载图片过程中的方法,它的子类都是实现了这个父类。
into()方法的作用:
①初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),②使用最原始的HTTPConnect网络连接,读取文件流,③根据文件判断是GIF动图还是Bitmap静态图片,④通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件。
into(ImageView imageView)方法:
@Override
public Target into(ImageView view) {
return super.into(view);
}
调用父类GenericRequestBuilder的into方法
public Target into(ImageView view) {
//断言是不是在主线程 因为ui更新操作在主线程
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
into方法最终会调用into(Target target)方法返回一个target对象,通过glide.buildImageViewTarget(view, transcodeClass)创建一个target对象
public > Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
//RequestTracker类用于跟踪、取消和重新启动进程中、已完成和失败请求
//执行请求
requestTracker.runRequest(request);
return target;
}
@Override
public void setRequest(Request request) {
setTag(request);
}
这里首先还是检查是不是在主线程,因为更新ui的操作必须在主线程,这里首先会通过target对象获取request对象,然后清除之前的request对象,回收request对象,然后重新构建一个新的request对象,并且给这个target设置request对象,这其实就是好比listView加载图片时候给图片设置tag,防止图片错位问题,这里requestTracker.runRequest这个方法就是执行图片请求的方法
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();// begin方法: 真正执行request请求的方法
} else {
pendingRequests.add(request);
}
}
注意点
1、对于Application类型参数:
在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
如果传入的就是Application类型参数(Glide.with(getApplicationContext())),那么会通过getApplicationManager()方法返回RequestManager。Glide加载图片的生命周期是和with里的参数保持一致,而对于Application类型,只有当应用程序被杀掉的时候,图片加载才会停止。
2、Glide添加请求头 cookie
GlideUrl glideUrl = new GlideUrl(url, new Headers() {
@Override
public Map getHeaders() {
Map header = new HashMap<>();
//不一定都要添加,具体看原站的请求信息
header.put("Referer", "http://www.baidu.com");
return header;
}
});
Glide.with(context).load(url).into(imageView);
Glide的核心思想:
- 对象池:
Glide原理的核心是为bitmap维护一个对象池。对象池的主要目的是通过减少大对象内存的分配以重用来提高性能。 - 生命周期绑定:
第一个with方法,这个其实就是一个工厂方法,虽然有许多重载的形式,其实都是要创建一个RequestManager对象。
创建一个透明的 RequestManagerFragment 加入到FragmentManager 之中
通过添加的这个 Fragment 感知 Activity 、Fragment 的生命周期。
图片的加载任务会与activity或者Fragment的生命周期绑定,当界面执行onStop的使用自动暂定,而当执行onStart的时候又会自动重新开启,同样的,动态Gif图的加载也是如此,以用来节省电量,同时Glide会对网络状态做监听,当网络状态发生改变时,会重启失败的任务,以减少任务因网络连接问题而失败的概率。
- 预览图的使用
为加快加载速度,提高体验,优先加载预览图 - AbsListView内图片的预加载:
https://www.jianshu.com/p/9d8aeaa5a329