前言
Android中加载图片的形式有很多种,网上也有很多的知名图片加载库,例如Glide、Picasso、Fresco等等,它们为我们带来的方便就不需再多言了,无论是从加载到缓存还是占位图等等都提供了简易的Api,且实现强大的功能。本系列只针对Glide4.0版本源码进行分析,提高自身阅读源码的能力,同时也是为了了解其中加载的流程以及缓存的原理,本文尽可能地截图说明结合源码解析,如有疏忽之处,还请指教。
关于作者
片头(Glide的基本使用)
1.首先肯定是添加依赖:
dependencies {
compile 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
}
2.流式调用,一行代码实现加载:
//加载本地资源
Glide.with(context).load(R.drawable.ic_android).into(imageView);
//加载网络图
Glide.with(context).load("http://....").into(imageView);
//裁剪为圆形
Glide.with(context).load(R.drawable.ic_android).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(imageView);
剧情(Glide.with 粮草先行)
由于3.0版本和4.0版本稍有差别,本文以4.0进行分析,Glide表面上简洁的调用,背后隐藏了很多的模块和复杂的逻辑,不然也没法做到这么强大的功能。可以看到,我们一般的使用是Glide.with(context).load(xxx).into(imageView);
,那就从此处作为入口着手分析。
Glide.with()
首先看Glide的with方法,我这里是在Activity调用的,进去之后是这样的:
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
可以看到这里,乍一看是获取一个RequestManager(RequestManager是请求相关的管理器,后文会提到,这里先略过),然后可以看到,Glide类中还有很多的重载方法:
看起来是为了适应不同的场景,但内部最终都是调用到
getRetriever(Context context)
方法,那我们再进入到getRetriever():
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
先是判断了传进来的context是否为空,然后调用了Glide.get(context).getRequestManagerRetriever()
,先看Glide.get(context)
:
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
这里采用了设计模式中的单例模式的DCL写法,以保证整个应用中只有一个Glide实例,方便统一管理和调度。然后再调用getRequestManagerRetriever
:
@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
返回了一个RequestManagerRetriever实例,那么RequestManagerRetriever是干嘛的呢?
/**
* A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or
* retrieving existing ones from activities and fragment.
*/
public class RequestManagerRetriever implements Handler.Callback {
//忽略部分代码...
@NonNull
public RequestManager get(@NonNull 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);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment);
}
}
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(@NonNull android.app.Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException(
"You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm, fragment);
}
}
@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(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
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);
current.setRequestManager(requestManager);
}
return requestManager;
}
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
@Nullable Fragment parentHint) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
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);
current.setRequestManager(requestManager);
}
return requestManager;
}
@NonNull
RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current,
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
/**
* Used internally to create {@link RequestManager}s.
*/
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
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);
}
};
}
这里源码有点长,先整体贴出来方便观看整体结构,嫌弃长的话可以先接着看,后面步骤会从代码里截图分步分析
里面同样重载了很多get方法,参数照样是Activity、Fragment、View、Context等多种类型(先留个疑问,为什么Glide要这么做呢?)首先看第一个get(Context context)
,可以看到里面对Context的类型做了判断。
getApplicationManager如果是在子线程或者Application中调用的话,会调用
getApplicationManager()
来获取RequestManager
如果是主线程或者普通Context的话均会走各自的get方法,但其实它们本质最后只会调用到fragmentGet
或者supportFragmentGet
其他普通Context获取的RequestManager
fragmentGet
然后再由它们将当前的Context的传递RequestManagerFactory
的build
方法,new出了我们需要的RequestManager对象:
可以看到,两条线路的主要区别在于传进去的Lifecycle参数不一样,Application传进去的是ApplicationLifecycle
,而Activity、Fragment等传进去的是getRequestManagerFragment()获得的Fragment对象的Lifecycle,那么getRequestManagerFragment
获取的是什么Fragment呢?,可以看到获取的是Glide创建的一个隐藏的Fragment——RequestManagerFragment
。RequestManagerFragment部分源码如下:
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
@VisibleForTesting
@SuppressLint("ValidFragment")
RequestManagerFragment(@NonNull 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();
}
}
不难看出,只要这个Fragment的生命周期一变化,就会调用lifecycle的对应函数,那么ActivityFragmentLifecycle的对应函数又是干嘛的呢?
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
这里用到了观察者模式,即一旦它的onStart、onStop等函数被外界调用时,就会相应的遍历调用所持有的lifecycleListener对象的生命周期函数,结合上一步,也就是说:Fragment的生命周期一变化,就会调用到ActivityFragmentLifecycle类的生命周期函数,进而触发所有监听它的lifecycle监听器(可还记得刚才提到创建RequestManager的时候是传进去了我们的ActivityFragmentLifecycle,到时候RequestManager中会调用这里的addListener(this),那么RequestManager就相当于监听了ActivityFragmentLifecycle,就相当于我们平时写监听事件原理差不多)。
Glide正是利用这个隐藏的Fragment来监听所在页面的生命周期,从而控制我们的图片加载的生命周期(比如页面销毁了就停止加载图片),所以这也就是Glide要重载多个不同类型Context方法的原因,因为Application的Context是随着整个应用的生命周期变化而变化,Glide只要跟随着应用生命周期就可以了,但是如果只是具体页面那肯定有各自单独的生命周期,因此要区分各个场景来进行初始化。
RequestManagerRetriever分析完毕,其实它就是用来绑定当前生命周期并且返回我们所需要的RequestManager,还记得吗,刚才我们第一步获取RequestManager对象的时候,是调用的如下代码:
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
getRetriever刚才也已经说了,是返回一个RequestManagerRetriever实例,那么这个时候调用的正是RequestManagerRetriever的get(Activity activity)方法,也就是说,Glide.with()方法会把我们当前所在的上下文Context传给Glide的RequestManagerRetriever生成对应的RequestManager对象。(此处以Activity为例, 会把我们的Activity实例传到RequestManagerRetriever中并且生成对应的RequestManager)
片尾
至此,Glide.with完成了它的使命。通过它绑定好了生命周期,并且拿到了接下来做请求要涉及到的RequestManager对象。
下集预告(Glide load 初露锋芒)
关注Android开发小栈,更多原创精选