前言
和之前的文章会有一定的不同,这主要是因为Glide
自身的源码量导致的问题,因为我是最后写的前言,你会发现在文章刚开始时会代码复制的比较完全,后面就比较零散,而且一部分我直接用自己话去进行了表述。如果真的要看懂,建议还是对着Glide
的源码进行查看,这样会帮助你更好去理解GLide
的它的实现流程。
使用方法(1)资源引入
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
(2)方法使用
// 实现单张图片加载
@Override public void onCreate(Bundle savedInstanceState) {
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
// 如果是最新版的系统是不允许http来进行请求的
// 去百度随便拿一张图片的地址来改一下就好了
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// 实现图片列表加载
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
Glide
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
源码分析在源码使用中,其实基础的在上面的使用方法中已经讲述到了,一共可以分为三个步骤:
- with(Context)
- load(ImageURL)
- into(ImageView)
我们的分析流程也将围绕这三个函数来进行展开。
with(Context)
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
悄咪咪数了数,Oh my Gosh!!! 竟然高达有6个重载方法。不过呢想必你也发现这些方法都直接调用了getRetriever().get()
的方法,那目的就非常明显了,我们进到这个方法去一探究竟了。
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever(); // 1 -->
}
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
// 使用了context.getApplicationContext()是为了防止内存泄漏的发生
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
// 对glide整体地进行初始化
// 其中就包含了对RequestManagerRetriever的初始化流程
// 代码量比较大就不做介绍了
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
既然是一堆的初始化操作,最后我们的目标又是RequestManagerRetriever
这个类,那自然是有必要对这个类进行探究的。
public class RequestManagerRetriever implements Handler.Callback {
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
private static final RequestManagerFactory DEFAULT_FACTORY =
new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
// getRetriever()的get()方法
// 对标上面的6个重载方法的调用,这里只取其一
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
// 如果当前的线程是在后台线程中,则进入
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext()); // 1-->
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); // 2 -->
}
}
}
(1)通过构造函数我们能够猜测的内容是通信的工具是Handler
,而Looper
使用的是MainLooper
也就是主线程的,那说明最后异步通信也就直接扔到主线程完成了。
(2)通过get()
函数,可以发现其实分为两个部分。一是再一层的get()
方法;二是supportFragmentGet()
或者是FragmentGet()
方法。
他们最后的任务都是为了创建出一个RequestManager
,但是我们得关注一下它的创建方式。
get()
对于这个方法而言就是对context
的判定是否为Application
,然后给出相应的结果。
(1)不是Application
且是在主线程中时
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
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
而他们的归宿,最后还是回到我们上方的重载方法。
(2)是Application
或是不再主线程时
getApplicationManager(context); // 1 -->
// 使用DCL的方式来创建了单例
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(), // 2
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
通过工厂来自建了一个RequestManager
,注释2处他直接使用了ApplicationLifecycle
原因是因为某些情况下会接受不到生命周期的事件,这里是做的强制性的操作是为了生命周期变化时能够正常相应。
FragmentGet()
瞟了一下,这是要一个废弃的方法了,但是和supportFragmentGet()
的方法相比其实也差不太多。
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); // 1 -->
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
// 将requestManager和Fragment相挂钩
// 用以完成生命周期的监听
current.setRequestManager(requestManager);
}
return requestManager;
}
// 1 -->
// 获取对应的Fragment
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
// 寻找的方式是通过设置的TAG
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
// 先去等待队列中进行查询
// 这一步的作用是防止Fragment的重复添加
// 因为添加的Fragment的所谓的生命周期有一定的延时性
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
// 如果等待队列创建一个新的TAG
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
总结
- 初始化
Glide
的同时在内部完成了RequestManagerRetriever
的创建 - 获取到的
RequestManagerRetriever
调用get()
方法,获取到RequestManager
,获取方式分为以下两种:
Context
为Application
时, 通过getApplicationManager()
方法创建RequestManager
完成,将生命周期的监听与Application
强制绑定用于接收。Context
不为Application
时, 通过supportFragmentGet()
方法创建RequestManager
完成,生命周期的监听是与Fragment
进行绑定实现。
创建对应TAG的一个非常直接的好处,我们的图片像RecyclerView
会放置中不容易出现错位的现象。
load(ImageURL)
总体来说上面的就是一个初始化和必要变量获取的操作,那接下从函数方法来看我们似乎是要去获得的图片了呢。
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string); // 1 -->
}
注释1处,我们通过观察可以知道他最后会选择将获取的数据转化变成一个Drawable
的类然后再在我们对应的ImageView
上来进行显示。那我们就对asDrawable()
先进行一段源码的分析。
// asDrawable()不断深入能发现调用到的函数
// 是完成一个类RequestBuilder的对象创建
public RequestBuilder as(
@NonNull Class resourceClass) { // Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
}
那接下来的问题就要进入到这个类中,因为在前面我们的探索其实算是并没有什么收获的,而如果只是创建一个类显然是不会让这句话显得这么重要,那关键点一定会出现在这个类的构造中了。
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners()); // 1 -->
// 这段代码过长,不做展示,它的主要任务就是一些策略开关
// 各种选项的开启装置,比如错误提示、优先级、磁盘缓存策略、固定宽高等等
apply(requestManager.getDefaultRequestOptions());
}
// 1-->
// 从某种意义上讲就是对生命周期的监听
private void initRequestListeners(List> requestListeners) {
for (RequestListener