1.Glide
Glide是Google主导的图片加载开源库。它有很多优势:
①使用简单,链式调用。
②支持多种图片格式,如Gif、WebP、缩略图、Video等。
③支持生命周期集成。Glide可以感知调用页面的生命周期,根据Activity或Fragment的生命周期管理图片加载请求。
④支持内存缓存和磁盘缓存。Picasso只会缓存原始尺寸的图片,Glide可以缓存多种规格;Glide加载速度快且内存开销小(glide使用RGB565)。
⑤高效处理Bitmap。支持bitmap的复用和主动回收,减少系统回收压力。使用Glide加载图片时,Glide会默认根据View视图对图片进行压缩和转换,而不显示原始图。这也是Glide加载速度高于Picasso的原因。
Glide缺点:太大了(不是轻量级的)
2.Glide的使用
Glide图片加载流程:
①一个完整的Glide请求至少需要三个参数:
Glide.with(context).load(url).into(imageView);
context上下文,可以使用Activity、Fragment、Context、ApplicationContext对象。推荐使用Activity或Fragment对象作为参数,这样图片的加载会和Activity/Fragment的生命周期保持一致,例如:onPaused时暂停加载,onResume时又会自动重新加载。而使用ApplicationContext时,图片加载会和application生命周期保持一致。
②占位图
.placeholder(R.drawable.place_image) 加载前显示的图片资源。
.error(R.drawable.error_image) 加载失败显示的图片资源。
.fallback(R.drawable.fallback_image) 传递加载资源为null时显示的图片资源。
注意:placeholder()和error()的参数都只支持int和Drawable类型的参数,因为使用本地图片比网络图片更加合适做占位图。
③缩略图
缩略图会在事件请求加载完成或者处理完之后显示。在原始图片到达之后,缩略图不会取代原始图片,只会被抹除。
Glide提供了2种缩略图的加载方式,比较简单的方式是调用thumbnail()方法,参数是float类型,表示倍数大小。例如传入0.2f作为参数,Glide将会显示原始图片20%的大小,如果原图是1000x1000的尺寸,那么缩略图将会是200x200的尺寸。因为缩略图明显比原图小得多,所以需要确保ImageView的ScaleType设置正确。
Glide.with(context).load(url).thumbnail(0.2f).into(imageView);
注意:应用于请求的设置也将应用于缩略图。
使用thumbnail()方法设置是简单粗暴的,但是如果缩略图需要通过网络加载相同的全尺寸图片,就不会很快的显示了。所以Glide提供了另一种方式去加载缩略图。
DrawableRequestBuilder<String> thumbnailRequest = Glide.with(context).load(url);
Glide.with(context).load(url)
.thumbnail(thumbnailRequest)
.into(imageView);
与第一种方式不同的是,这里的第一个缩略图请求是完全独立于第二个原始请求的。该缩略图可以是不同的资源图片,同时也可以对缩略图做不同的转换等。
④载入动画
.crossFade()默认是开启的,并且本身默认动画的时长是300ms。
如果不需要默认动画效果,可使用.dontAnimate() 禁用动画效果。
⑤缓存处理
Glide的缓存分为内存缓存和硬盘缓存。缓存的读取顺序为:内存缓存 –> 磁盘缓存 –> 网络 ,内存缓存和磁盘缓存相互不影响,独立配置。
内存缓存:防止应用重复将图片读入到内存,造成内存资源浪费。内存缓存只缓存转换后的图片,而不是原始图片。内存缓存是默认开启的,可以通过skipMemoryCache(false)关闭。Glide的内存缓存使用的是LruCache算法,同时使用了弱引用机制。
磁盘缓存:防止应用重复从网络或其他地方下载和读取数据。磁盘缓存可根据用户设置来缓存原始图片或转换过后的图片。磁盘缓存默认是开启,可以通过设置diskCacheStrategy( DiskCacheStrategy.NONE)关闭。
如果Glide不需要缓存,可以这样写:
Glide.with(context).load(url)
.skipMemoryCache(false)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView);
DiskCacheStrategy枚举的意义:
DiskCacheStrategy.NONE 什么都不缓存
DiskCacheStrategy.DATA 只缓存原始图片
DiskCacheStrategy.RESOURCE 只缓存转换过后的图片
DiskCacheStrategy.ALL 既缓存原始图片,也缓存转换过后的图片
DiskCacheStrategy.AUTOMATIC 默认,Glide会根据图片资源智能地选择使用哪一种缓存策略
默认的存储路径是内置存储的沙盒环境cache/image_manager_disk_cache目录。
注:Glide加载一张图时,默认不会展示原图,而是会对图片进行压缩和转换,比如对图片进行尺寸压缩到目标View大小。
⑥支持Gif&视频
.asGif():校验是否是一个Gif,如果不是,则认为是一次错误的加载。使用asGif()进行校验,如果当前加载的图片不是一个正确的Gif格式,则会去显示error()配置的图片。有时候可能只为显示一张图片,可以强制显示Gif 图片的第一帧,用asBitmap()方法替代asGif()即可。
Glide还能显示视频(只能显示手机本地的视频)。但不会去播放视频文件,而只是将视频文件的第一帧做为一个图片显示出来。
String filePath = "/storrage/emulated/0/Pictures/video.mp4";
Glide.with(context )
.load(Uri.fromFile( new File( filePath ) ) )
.into(imageView );
⑦加载监听
可以使用listener()方法对Glide加载图片的结果进行监听,它接收一个RequestListener的接口。
RequestListener requestListener = new RequestListener() {
@Override
public boolean onLoadFailed(GlideException e, Object model, Target target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
return false;
}
};
Glide.with(context).load(url)
.listener(requestListener)
.into(imageView);
如果需要监听图片加载错误的原因,可以在 onLoadFailed()中做处理。
注意,这两个方法的返回值,最好都是false。因为如果返回true表示已经处理了这次的事件,而Glide将不会再做额外的处理。例如,如果onLoadFailed()返回了true的话,在图片加载失败之后,error()中设置的图片,并不会被显示,因为Glide认为开发者已经在外部对这个错误进行了处理。
⑧变换加载的图片
想要在图片显示之前,对其进行一些变换操作,例如改变颜色、虚化、圆角之类的,就需要用到transfrom()方法,它主要用于在图片显示之前自定义变换效果。
变换有两个方法:
transfrom():可以添加一个通用的变换效果。
bitmapTransfrom():限制了变换的类型,只能设置Bitmap的变换。
3.源码解析Glide.with()
Glide.with()有多个重载方法,参数可以为Context、Activity、FragmentActivity、Fragment、View。
public static RequestManager with(Context context) { //与Application的生命周期相关联,将不受Activity/Fragment生命周期影响。该方法适用于在正常Activity/Fragment之外使用资源,例如在Service或notification中
return getRetriever(context).get(context);
}
public static RequestManager with(Activity activity) { //与activity生命周期相关联
return getRetriever(activity).get(activity);
}
public static RequestManager with( FragmentActivity activity) { //与FragmentActivity生命周期相关联
return getRetriever(activity).get(activity);
}
public static RequestManager with(Fragment fragment) { //与Fragment生命周期相关联
return getRetriever(fragment).getContext().get( fragment);
}
public static RequestManager with(View view) { //与包含该view的Fragment或Activity的生命周期相关联
return getRetriever(view.getContext()).get( view);
}
with()方法最终要返回RequestManager实例,获取RequestManager分为两步:第一步getRetriever()获取RequestManagerRetriever实例,第二步RequestManagerRetriever.get()获取RequestManager实例。
①第一步 getRetriever()获取RequestManagerRetriever实例。
private static RequestManagerRetriever getRetriever(Context context) {
return Glide.get(context).getRequestManag erRetriever(); //创建Glide实例和RequestManagerRetriever实例,并返回RequestManagerRetriever实例
}
主要看使用单例模式获取Glide实例:
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
private static void checkAndInitializeGlide(){
initializeGlide(context, generatedAppGlideModule);
}
private static void initializeGlide(Context context, GeneratedAppGlideModule annotationGeneratedModule) {
initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}
private static void initializeGlide(Context context, GlideBuilder builder, GeneratedAppGlideModule annotationGeneratedModule) {
……
Glide glide = builder.build(applicationContext); //通过build创建Glide实例,在创建Glide实例过程中初始化了requestManagerRetriever实例
Glide.glide = glide;
}
最终调用了GlideBuilder.build()方法构建Glide实例:
Glide build(Context context) {
……
RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory, experiments); //创建requestManagerRetriever对象,可见RequestManagerRetriever对象的创建是在Glide的初始化过程中完成的
return new Glide(context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptionsFactory, defaultTransitionOptions, defaultRequestListeners, experiments);//创建Glide实例,并将新建的requestManagerRetriever实例赋值给Glide的requestManagerRetriever属性
}
RequestManagerRetriever的作用是创建和复用RequestManager,使用RequestManagerRetriever.RequestManagerFactory工厂创建RequestManager,复用SupportRequestManagerFragment中已有的RequestManager。
②第二步 requestManagerRetriever.get()创建并返回RequestManager实例。
根据get()的参数不同,有不同的重载方法。
public RequestManager get(Context context) {
if(Utils.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 && ((ContextWrapper)context).getBaseContext( ).getApplicationContext() != null) {
return get(((ContextWrapper)context).getB aseContext());
}
}
return getApplicationManager(context);
}
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else { //添加一个空白Fragment,用于关联生命周期
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null, isActivityVisible(activity));
}
}
public RequestManager get(Fragment fragment){
if (Util.isOnBackgroundThread()) {
return get(fragment.getContext().getApplic ationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet( fragment.getContext(), fm, fragment, fragment.isVisible());
}
}
public RequestManager get(Activity activity){
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else if(activity instanceof FragmentActivity) {
return get((FragmentActivity)activity);
} else {
android.app.FragmentManager fm = activity.getFragmentManager();
return FragmentGet(activity, fm, null, isActivityVisible(activity));
}
}
首先判断当前是否在主线程,如果不是主线程,直接转到get(activity.getApplicationContext())中执行;否则继续调用supportFragmentGet()方法添加空白Fragment。
这里有一个面试题:为什么不在子线程里调用Glide.with()?因为在子线程里不会去添加生命周期机制,只有在主线程中才会添加空白Fragment监听Activity/Fragment生命周期的变化。如果在子线程中调用with,那么图片加载的生命周期会与application一致,而不会随activity/fragment的生命周期变化而变化,也就是application销毁时图片才会停止加载。
(1)supportFragmentGet()方法
主要作用是创建空白Fragment,并返回它对应的RequestManager对象。
private RequestManager supportFragmentGet( Context context, FragmentManager fm, Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); //创建空白Fragment
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); //工厂模式创建requestManager
if (isParentVisible) {
requestManager.onStart();
}
current.setRequestManager( requestManager); //requestManager存储到空白的Fragment中
}
return requestManager;
}
SupportRequestManagerFragment就是空白的Fragment,它用于安全存储RequestManager,空白Fragment会添加到当前Activity,利用空白Fragment的生命周期变化来控制图片的加载流程。
(2)getSupportRequestManagerFragment()方法
获取空白Fragment,Glide通过空白Fragment来感知生命周期。
RequestManagerRetriever.java:
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments = new HashMap<>(); //缓存已添加的空白Fragment
private SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm, Fragment parentHint) {
SupportRequestManagerFragment current =(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//检查是否已经添加了空白Fragment
if (current == null) {
current=pendingSupportRequestManagerFra gments.get(fm);//查找FragmentManager中是否有可以复用的SupportRequestManagerFragment
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint( parentHint);
pendingSupportRequestManagerFragmen ts.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPP ORT_FRAGMENT_MANAGER, fm).sendToTarget(); //空白Fragment与Activity关联
}
}
return current;
}
首先检查FragmentManager中是否有可以复用的空白Fragment,如果没有就查找pendings中是否已经添加了空白Fragment,如果还是没有找到就新建一个,并添加到pendings列表,同时提交到FragmentManager。
(3)SupportRequestManagerFragment类
现在空白的SupportRequestManagerFragment已经添加成功,看一下它的源码:
public class SupportRequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
public SupportRequestManagerFragment( ActivityFragmentLifecycle lifecycle) {
this.lifecycle = 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();
}
}
在SupportRequestManagerFragment里新建了一个ActivityFragmentLifecycle实例赋值给空白Fragment的lifecycle成员变量。
(4)RequestManager类
RequestManager是由工厂模式创建的,上面代码中的factory是RequestManagerFactory类型。
默认使用DEFAULT_FACTORY来创建RequestManager。
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@Override
public RequestManager build(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode requestManagerTreeNode, Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
看一下RequestManager的构造方法:
public class RequestManager implements LifecycleListener {
RequestManager(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) {
……
if (Util.isOnBackgroundThread()) {
Util.postOnUiThread(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
glide.registerRequestManager(this);
}
private final Runnable addSelfToLifecycle = new Runnable() {
@Override
public void run() {
lifecycle.addListener( RequestManager.this);
}
};
}
RequestManager实现了LifecycleListener接口,在RequestManager构造方法中,把当前空白Fragment对应的RequestManager添加到lifecycle。lifecycle是ActivityFragmentLifecycle类型,在SupportRequestManagerFragment构造方法中创建。
(5)ActivityFragmentLifecycle类
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners= Collections.newSetFromMap( new WeakHashMap<LifecycleListener, Boolean>()); //储存LifecycleListener的列表
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(LifecycleListener listener) {
lifecycleListeners.add(listener); //向lifecycleListeners列表添加LifecycleListener
//添加完成后,根据状态执行对应的回调方法
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {//遍历执行onStart
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
使用观察者模式,在组件生命周期发生变化的时候回调相应的操作方法。这一切都是框架完成的,前面在RequestManager构造函数中把RequestManager自身(实现了LifecycleListner接口)加入到了ActivityFragmentLifecycle的成员变量lifecycleListeners中。
监听组件生命周期流程汇总:
①创建空白SupportRequestManagerFragment绑定到当前Activity。
SupportRequestManagerFragment持有RequestManager实例。RequestManager实例由RequestManagerRetriever创建并传递给SupportRequestManagerFragment 。
②RequestManager持有ActivityFragmentLifecycle引用。lifecycle在SupportRequestManagerFragment构造方法中产生并传递给RequestManager。
RequestManager在构造函数中把自己加入到ActivityFragmentLifecycle.lifecycleListeners列表。
③生命周期同步过程,以Activity调用onStart()为例:
1)Activity调用onStart()
2)SupportRequestManagerFragment调用onStart()
@Override
public void onStart() {
super.onStart();
lifecycle.onStart(); //==ActivityFragmentLifecycle.onStart()
}
3)lifecycle调用onStart()
ActivityFragmentLifecycle#onStart()
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart(); //==RequestManager.onStart()
}
}
4)RequestManager调用onStart()
RequestManager#onStart()
@Override
public synchronized void onStart() {
resumeRequests(); //启动图片加载请求
targetTracker.onStart(); //添加到Target tracker ,统一管理targets响应组件生命周期
}
图片加载时感知组件生命周期全过程:
5.Glide#load()
with()方法返回的是一个RequestManager对象,说明load()方法是在RequestManager类中,所以首先要看的就是RequestManager类。
load()方法支持多种形式的图片来源,以RequestManager类中的load(String string) 方法为例分析。
@Override
public RequestBuilder<Drawable> load(String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as( Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
load(String string)最终被分为两步执行:
①第一步 以Drawable.class为参数创建RequestBuilder实例。
protected RequestBuilder(Glide glide, RequestManager requestManager, Class<TranscodeType> transcodeClass, Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass; //传进来的Drawable.class赋值给transcodeClass变量
……
}
②第二步 调用RequestBuilder#load(String string)
public RequestBuilder<TranscodeType> load(String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(Object model) {
this.model = model; //传进来的String赋值给model变量
isModelSet = true;
return selfOrThrowIfLocked();
}
RequestBuilder重要成员变量:
1)transcodeClass = Drawable.class, 构建ImageViewTarget的时候使用;
2)model = 图片来源为String地址,构建Request的时候使用;
RequestManager#load(String string)只是新建了RequestBuilder,并给它的两个属性分别赋值。
6.Glide#into()
public ViewTarget<ImageView, TranscodeType> into(ImageView view) {
……
return into(
glideContext.buildImageViewTarget(view, transcodeClass), //构建新的ImageViewTarget
null, requestOptions,
Executors.mainThreadExecutor()); //主线程池,切回到主线程显示图片
}
private <Y extends Target<TranscodeType>> Y into(Y target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
Request request = buildRequest(target, targetListener, options, callbackExecutor); //构建新的加载请求Request
Request previous = target.getRequest(); //获取目标View上已经存在的旧请求
if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { //如果两次的请求相同 && !(跳过内存缓存 && 旧请求已完成),into()方法直接返回target
if (!Preconditions.checkNotNull( previous).isRunning()) { //如果旧请求未开始
previous.begin(); //启动旧请求
}
return target;
}
requestManager.clear(target); //取消Glide为target准备的所有加载请求,并释放已经加载的资源(例如Bitmap),以便它们可以被重用
target.setRequest(request); //利用View.setTag把request请求绑定到target指向的View
requestManager.track(target, request); //调用track方法
return target;
}
private boolean isSkipMemoryCacheWithCom pletePreviousRequest(
BaseRequestOptions<?> options, Request previous) {
return !options.isMemoryCacheable() && previous.isComplete();
}
track方法分析:
RequestManager.java:
synchronized void track(Target<?> target, Request request) {
targetTracker.track(target); //target添加到targetTracker,管理target指向的View生命周期回调事件
requestTracker.runRequest(request); //request添加到requestTracker,管理图片加载请求
}
targetTracker和requestTracker都是RequestManager的成员变量,分别负责管理target和request。
TargetTracker的职责是维护一个Target列表,统一管理所有Target的onStart()、onStop()和onDestroy()方法回调事件。
public final class TargetTracker implements LifecycleListener {
private final Set<Target<?>> targets = Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>()); //维护target列表
public void track(Target<?> target) {
targets.add(target);
}
public void untrack(Target<?> target) {
targets.remove(target);
}
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
@Override
public void onDestroy() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onDestroy();
}
}
public List<Target<?>> getAll() {
return Util.getSnapshot(targets);
}
public void clear() {
targets.clear();
}
}
RequestTracker部分源码:
public class RequestTracker {
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>()); //如果Set直接持有request强引用,可能会发生内存泄漏,因此将request作为key存储在WeakHashMap里面,如果这些key不再使用,WeakHashMap会自动移除这些key,从而避免内存泄漏
private final Set<Request> pendingRequests = new HashSet<>(); //直接持有未完成和等待开始的request强引用对象,防止在运行过程中被GC
private boolean isPaused; //所有请求是否已经被暂停
//把请求添加到requests和pendingRequests(Glide维护了两个队列,一个正在运行队列,一个等待执行队列)
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
pendingRequests.add(request);
}
}
//停止正在运行的请求
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
//开启未完成或失败的请求
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
}
综上,Glide管理图片加载请求的方式并不复杂:使用一个请求管理类RequestTracker维护所有请求列表,并且提供统一操作所有请求的方法(即所有请求的开启、暂停和重启等等方法),RequestManager只要通过一个RequestTracker对象就能轻轻松松控制图片加载请求。
6.图片加载请求执行流程
RequestTracker用来管理图片加载请求,来分析一下图片加载请求执行流程。
RequestTracker.java:
//把请求添加到requests和pendingRequests
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin(); //图片加载请求执行入口
} else {
request.clear();
pendingRequests.add(request);
}
}
request.begin()方法是请求开始执行的入口,这里的request是SingleRequest类型。
看一下SingleRequest类:
public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback {
private enum Status { //请求的状态
PENDING, //已创建,但尚未执行
RUNNING,
WAITING_FOR_SIZE, //Waiting for a callback given to the Target to be called to determine target dimensions
COMPLETE,
FAILED,
CLEARED, //Cleared by the user with a placeholder set, may be restarted
}
private final Object requestLock; //同步锁对象
//监听请求的状态变化
private final RequestListener<R> targetListener;
private final RequestCoordinator requestCoordinator;//协调一个target上的多个请求
private final Context context;
private final Target<R> target;
private final List<RequestListener<R>> requestListeners;
private volatile Engine engine; //图片处理引擎
@Override
public void begin() {
synchronized (requestLock) {
if (model == null) { //如果资源数据为null,执行onLoadFailed()方法
onLoadFailed(new GlideException( "Received null model"), logLevel); //加载失败
return;
}
if (status == Status.RUNNING) { //请求状态为RUNNING,不允许执行begin()方法
throw new IllegalArgumentException( "Cannot restart a running request");
}
if (status == Status.COMPLETE) { //请求状态为COMPLETE时会执行onResourceReady方法
onResourceReady(resource, DataSource.MEMORY_CACHE, false);
return;
}
experimentalNotifyRequestStarted(model);
status = Status.WAITING_FOR_SIZE; //状态设为:等待target确定尺寸
if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //如果通过RequestOption设置的宽高都大于0或者与Target原始宽高相等,则调用onSizeReady(overrideWidth, overrideHeight);;否则重新计算target尺寸,计算完成后依然会调用onSizeReady()方法
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { //target设置占位图
target.onLoadStarted( getPlaceholderDrawable());
}
}
}
}
1)资源数据为null时会执行onLoadFailed(new GlideException("Received null model"), logLevel)方法:
private void onLoadFailed(GlideException e, int maxLogLevel) {
synchronized (requestLock) {
loadStatus = null;
status = Status.FAILED; //1.设置请求的状态为Status.FAILED
setErrorPlaceholder(); //2.如果不是缩略图请求,setErrorPlaceholder()设置显示失败占位图
}
@GuardedBy("requestLock")
private void setErrorPlaceholder() {
target.onLoadFailed(error); //3.告诉target资源加载失败,并把错误占位图资源回传给target
}
2)请求状态为COMPLETE时会执行onResourceReady(resource, DataSource.MEMORY_CACHE, false);方法:
public void onResourceReady(Resource<?> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
Resource<?> toRelease = null;
try {
synchronized (requestLock) {
loadStatus = null;
onResourceReady((Resource<R>) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey);
}
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource, boolean isAlternateCacheKey) {
status = Status.COMPLETE;
target.onResourceReady(result, animation);
notifyLoadSuccess();
}
3)如果通过RequestOption设置的宽高都大于0或者与Target原始宽高相等,则调用onSizeReady(overrideWidth, overrideHeight);否则重新计算target尺寸,计算完成后依然会调用onSizeReady()方法。
@Override
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING; //请求的状态设为RUNNING
loadStatus = engine.load(glideContext, model, requestOptions.getSignature(),this.width, this.height, requestOptions.getResourceClass(), transcodeClass, priority, requestOptions.getDiskCacheStrategy(), requestOptions.getTransformations(), requestOptions.isTransformationRequired(), requestOptions.isScaleOnlyOrNoTransform(), requestOptions.getOptions(), requestOptions.isMemoryCacheable(), requestOptions.getUseUnlimitedSourceGeneratorsPool(), requestOptions.getUseAnimationPool(), requestOptions.getOnlyRetrieveFromCache(), this, callbackExecutor); //图片加载引擎Engine开始加载图片
}
}
到此为止,Request的begin()方法分析完毕,图片加载流程最终交给Engine执行。Engine是整个图片加载流程中一个非常重要的角色。
Engine.java:
public <R> LoadStatus load(GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb, Executor callbackExecutor) {
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //使用request配置信息构建EngineKey,用作资源缓存时的key
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); //从正在使用的资源列表和内存缓存中查找资源
if (memoryResource == null) { //缓存中查找不到资源,重用或新建一个新EngineJob
return waitForExistingOrStartNewJob( glideContext, model, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, options, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache, cb, callbackExecutor, key, startTime);
}
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE, false);
return null;
}
private EngineResource<?> loadFromMemory( EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = loadFromActiveResources(key); //正在使用的资源列表中查找
if (active != null) {
return active;
}
EngineResource<?> cached = loadFromCache(key); //内存缓存中查找资源
if (cached != null) {
return cached;
}
return null;
}
内存缓存的流程图:
这里有个问题:LruCache只看到了取数据的过程,那什么时候存数据呢?其实存数据是在Engine.onResourceReleased()释放资源时,具体在于acquire引用计数器的作用:计数器>0说明图片正在使用,存在于activeResources弱引用map中;经过release()后若计数器=0说明图片不再被使用,就会调用上述方法释放资源,此时在该方法中会将当前没有使用的资源缓存到LruCache中。
注:Glide的图片缓存分为内存缓存和磁盘缓存,这里已经出现了内存缓存,磁盘缓存会在接下来的DecodeJob中处理。
private <R> LoadStatus waitForExistingOrStartNewJob(GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb, Executor callbackExecutor, EngineKey key, long startTime) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob = engineJobFactory.build(key,isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache);
DecodeJob<R> decodeJob = decodeJobFactory.build(glideContext, model,key, signature, width, height, resourceClass, transcodeClass, priority,diskCacheStrategy, /*磁盘缓存策略*/ transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
从EngineJob缓存列表中查找是否有可重用的EngineJob,如果有直接重用;否则新建一个EngineJob,并开启该JobengineJob.start(decodeJob);
EngineJob.java:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
解码工作是耗时操作,不能在主线程操作,因此把decodeJob提交到线程池执行:
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
@Override
public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {// 异常处理
} finally { //清理工作
}
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE); //计算nextStage
currentGenerator = getNextGenerator(); //根据nextStage获取对应的Generator
runGenerators(); //执行runGenerators()
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException( "Unrecognized run reason: " + runReason);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()? Stage.RESOURCE_CACHE : getNextStage( Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException( "Unrecognized stage: " + current);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator( decodeHelper, this); //缓存的处理过的资源的生成器
case DATA_CACHE:
return new DataCacheGenerator( decodeHelper, this); //缓存的原始资源的生成器
case SOURCE:
return new SourceGenerator( decodeHelper, this); //使用modelLoader和model获取原始资源的生成器
case FINISHED:
return null;
default:
throw new IllegalStateException( "Unrecognized stage: " + stage);
}
}
Glide的缓存机制简单总结就是:
若允许内存缓存,先从内存LruCache中查找,若存在则将该资源添加到activeResouces弱引用map中然后返回,该map主要用来缓存当前正在使用的资源,若不存在则判断activeResouces弱引用map中是否存在,若存在则返回,每次资源处于正在使用状态,则引用计数加一,若未使用,则缓存到LruCache中。若内存中不存在,若允许磁盘缓存,再从磁盘缓存中查找。若磁盘中不存在,则直接下载,然后再根据磁盘缓存策略缓存原图或是经转换后的图到磁盘中。