Glide的简介就不多说了,只要记住这是Google推荐AndroidDev使用的图片开源框架就好了。直接进入正题,看看Glide的设计到底有何精妙之处,为何获得了Google的青睐?
一个最简单的Glide图片加载逻辑举例:
Glide.with(context).load(url).into(imageView);
我们的分析会以Glide3.8.0版本为例,基于此行代码展开,分别分析with()、load()、into()三个方法内部的逻辑。
一、基础概念
Glide中涉及几个概念,为便于理解,先粗略解释:
1.Model
指的是对图片源的封装。在AndroidDev中,比较常见的就是网络图片地址、本地文件或资源ID。比如,String url = "https://www.baidu.com/img/bd_logo1.png",这里的url经过Glide内部的封装后,就可以理解为一个Model。
2.Data
指的是对Model处理后的数据源的封装,通常是InputStream。而在Glide中,将Model处理为Data的类便是ModelLoader。比如,通过上文的"https://www.baidu.com/img/bd_logo1.png"而取得的图片输入流,就可以理解为Data。
3.Resource
拿到图片的输入流可以直接展示在UI上吗?显然不可以。在第2点中我们提及了Data,即输入流,如果要将其展示就需要对Data进行解码,解码后的数据就是Resource。比如,上文的图片输入流经过解码后成为一个Bitmap对象或Drawable对象,这个对象就可以理解为Resource。而担任解码任务的角色,被成为ResourceDecoder(资源解码器)。
4.TransformedResource&TranscodedResource
有时候我们获取到的Resource并不适合展示,而是需要经过处理才能展示,比如需要裁剪变换等(如调用centerCrop()、fitCenter()),那么经过如此变换后的Rescourse称为TransformedResource。
我们知道Glide是可以展示静态图,也可以展示动态图(动态Gif),而解码后的静态图片和动态图片(例如drawable和gif-drawable)类型是不同的, 为了统一处理逻辑,Glide内部将这两种类型的对象再次封装为统一的GlideBitmapDrawable,这里的GlideBitmapDrawable就可以理解为TranscodedResource。
5.Target
这个比较容易理解,即需要在哪个目标上进行展示,比如ImageView。而Glide内部将ImageView再次进行了封装,封装后对象就可以理解为Target。
综上所述,一个完整的图片处理及展示流程如下:
二、基本用法
直接看代码和注释:
Glide.with(context)
.load(url)
.placeholder(R.mipmap.ic_launcher)//图片加载前的占位图
.error(R.mipmap.ic_launcher)//图片加载错误的占位图
.fitCenter()
.centerCrop()
.override(500, 500)//调整图片大小
.skipMemoryCache(true)//跳过内存缓存
.crossFade(1000)//渐变显示时间
.diskCacheStrategy(DiskCacheStrategy.RESULT)//缓存处理后的图像(如尺寸调整、裁剪后的图像)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)//缓存原尺寸的图像
.diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有图像
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
.priority(Priority.HIGH)//指定优先级
.into(imageView);
三、with()源码逻辑
跟进Glide类中寻找with()方法,发现with()方法有多种重载,包括with(Context context)、with(Activity activity)、with(Fragment fragment)等等。Glide之所以设计如此之多的with()方法重载,其目的在于将图片的加载与传入的Context组件或Fragment的生命周期相关联。比如,当用户关闭当前Activity,那么即使该Activity有正在进行中的图片网络请求,Glide也会随之取消该网络请求。如果传入的是ApplicationContext,那么网络请求会持续进行,直至App进程被销毁。
这里以with(Context context)为例看一下源码实现,其他重载方法逻辑基本一致:
Glide.java
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
RequestManager类是Glide中用来处理图片加载请求的管理类。RequestManagerRetriever类是用来创建和管理RequestManager对象的,其get()方法获取了RequestManagerRetriever实例。继续追踪源码,查看RequestManagerRetriever类中get()方法的逻辑。
RequestManagerRetriever.java
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);
}
在get()方法中,对Context的类型进行了区分,有多种重载。我们主要分析一下Application和Activity类型的方法参数,其他类型的参数读者可以自行追踪源码。
RequestManagerRetriever.java
private RequestManager getApplicationManager(Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
applicationManager = new RequestManager(context.getApplicationContext(),
new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
上述get(Application context)的方法中采取了双重锁单例模式获取了一个RequestManager对象。可以发现,Glide在RequestManager的构造方法中传入了ApplicationLifecycle的实例,其作用是将RequestManager与Application生命周期绑定。
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
上述get(Activity context)的方法中,首先进行了线程判断,如果在非主线程的情况下,返回了get(Application context)类型的RequestManager,而在主线程的情况下,通过该Activity context获取到了相关联的FragmentManager。这是Glide设计精妙之处之一,为什么要获取FragmentManger呢?继续追踪源码到fragmentGet(activity,fm)中。
RequestManagerRetriever.java
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
分析一下fragmentGet()的逻辑。首先,方法第一行getRequestManagerFragment()返回了RequestManagerFragment的实例current。RequestManagerFragment是啥?其实这是Glide封装的Fragment,这里当作Fragment来理解。先来截取部分RequestManagerFragment类的代码:
RequestManagerFragment.java
public class RequestManagerFragment extends Fragment {
......
private final ActivityFragmentLifecycle lifecycle;
private RequestManager requestManager;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
/**
* Sets the current {@link com.bumptech.glide.RequestManager}.
*
* @param requestManager The request manager to use.
*/
public void setRequestManager(RequestManager requestManager) {
this.requestManager = requestManager;
}
ActivityFragmentLifecycle getLifecycle() {
return lifecycle;
}
/**
* Returns the current {@link com.bumptech.glide.RequestManager} or null if none exists.
*/
public RequestManager getRequestManager() {
return requestManager;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
对RequestManagerFragment划重点:
1.含有一个RequestManager类型的成员变量requestManager,通过getRequestManager()返回,通过setRequestManager()赋值。
即每个RequestManagerFragment对象都与一个RequestManager对象绑定。
2.含有一个ActivityFragmentLifecycle类型的成员变量lifecycle。通过对lifecycle实现的LifecycleListener接口回调来监听其生命周期,可以发现在RequestManagerFragment类的onStart()、onStop()、onDestroy()方法中对其进行了调用。
即lifecycle对象实现了对RequestManagerFragment实例的生命周期监听。
回到fragmentGet()方法中,调用RequestManagerFragment中的getRequestManager()方法返回与其绑定的RequestManager对象(成员变量),如果为null(没有与其绑定的RequestManager对象),则创建一个RequestManager对象,并调用setRequestManager()将其与RequestManagerFragment绑定。至此实现了RequestManagerFragment对象与RequestManager对象的一一绑定。
现在思考一个问题,Glide如何监听目标Activity或Fragment的生命周期?上文已经说明,根据传入Glide的Context不同,Glide会监听其生命周期,根据生命周期管理图片的网络请求。
Glide直接监听Activity并不方便。那么在这里,Glide采用了另外的方法:
1.在Activity或Fragment的上层添再加一个Fragment,也就是上文一直在分析的RequestManagerFragment。这个Fragment并没有覆写createFragmentView(),即这是一个无UI的Fragment,当添加了该Fragment,用户是无法感知到的。
2.我们知道依附于Activity的Fragment有与被依附的Activity相关联的生命周期,监听Fragment的生命周期也就是获取到了被依附的Activity的生命周期。上文已经划过重点:RequestManagerFragment通过接口回调的方式,在onStart()、onStop()、onDestroy()中调用了ActivityFragmentLifecycle的相应生命周期方法,实现了对其生命周期的监听。
3.如果传入Glide.with()参数为Fragment,那么处理逻辑同上。大家应该也在Fragment中添加过Fragment吧?Glide同样监听了RequestManagerFragment的生命周期。
4.每个RequestManagerFragment对象又与RequestManager对象一一绑定。至此,所有疑问解开: