前言
在Glide框架使用及分析(一)中学习了Glide的基本使用方法,以其简单的API调用实现了图片加载功能,展现了这个图片加载框架的强大。
其在界面上加载图片只需要一行代码:
Glide.with(this).load(url).into(imageView);
仅仅这一行代码是如何进行图片加载的呢?Glide框架的内部是如何工作的?接下来我们就跟着这行代码窥探一下内部的奥秘吧!
以下代码的分析是基于Glide v4 版本的,有需要的朋友可以在github上面直接下载源码。
Glide.with()
首先我们看一下这个Glide的静态方法with()做了什么工作?
@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) {
Log.e(TAG, "with: --根据上下文获取RequestManager对象");
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);
}
Glide中有很多重载的with静态方法,看源码可以了解到重载方法的参数例如之前所说,包含context、activity、fragment、设置是view对象等,方法中调用了getRetriever(view.getContext()).get(view)返回了RequestManager对象,接下来我们具体看一下这句代码做了什么?
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
//检测context是否为空,如果为空则抛出异常
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();
}
@NonNull
// 这里是一个典型的双检锁单例模式
@SuppressWarnings("GuardedBy")
public static Glide get(@NonNull Context context) {
if (glide == null) {
//获取GeneratedAppGlideModuleImpl对象
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
1,getRetriever()此方法判断了传入的context是否为空,为空则抛出异常,不为空则调用了Glide.get()方法。
2,Glide.get()方法是一个典型的双检锁单例模式,主要是创建Glide对象,以及初始化Glide相关参数(Glide对象的创建以及初始化的参数比较复杂)。
3,通过Glide对象获取RequestManagerRetriever对象
4,调用RequestManagerRetriever中的get()方法,这个get()方法也有多个重载方法,如下所示:
@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
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
Log.e(TAG, "get: isOnBackgroundThread::"+Util.isOnBackgroundThread() );
//判断是否是后台线程,如果是则使用ApplicationContext重新获取
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//判断页面是否销毁
assertNotDestroyed(activity);
maybeRegisterFirstFrameWaiter(activity);
//获取当前页面的fragmentmanager
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(
fragment.getContext(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getContext().getApplicationContext());
} else {
maybeRegisterFirstFrameWaiter(fragment.getActivity());
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else if (activity instanceof FragmentActivity) {
return get((FragmentActivity) activity);
} else {
assertNotDestroyed(activity);
maybeRegisterFirstFrameWaiter(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(
view.getContext(), "Unable to obtain a request manager for a view without a Context");
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((FragmentActivity) activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
这里分析一下参数为fragmentactivity的:
1,首先判断一下是否是子线程执行,如果是子线程则直接强制使用ApplicationContext从新获取
2,判断页面是否销毁,如果没有在获取当前页面的fragmentmanager,
3,调用supportFragmentGet()方法来获取RequestManager对象:
//Glide是通过在页面中添加一个Fragment来动态监听页面的创建和销毁,
// 从而达到依赖页面生命周期,动态管理请求的目的
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
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);
if (isParentVisible) {
requestManager.onStart();
}
current.setRequestManager(requestManager);
}
return requestManager;
}
到此,我们的with方法中获取RequestManager对象就已完成。
来看下with方法执行的顺序图:
load()方法
接下来我们点击进入查看一下load()方法做了什么事情?在RequestManager类中,load()方法也有很多重载方法,着重看一下我们使用到的,如下所示:
/**
* 下载图片
* @param string url地址
* @return
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
Log.e(TAG, "load string url: "+string );
return asDrawable().load(string);
}
我们将url传入load()方法中,此方法先是调用了asDrawable()方法,这个方法主要是配置图片的信息,设置其显示的形式,主要调用了as()方法。
/**
* @return A new request builder for loading a {@link Drawable}.
* 配置图片的信息,
* 加载获取的图片资源是转换为drawable或者其他的例如bitmap或者GIF进行图片显示
*/
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
//初始化了RequestBinder对象,将Glide对象,requestmanager对象,以及图片class及上下文传入
Log.e(TAG, "as: 初始化了RequestBuilder对象" );
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as方法主要创建了一个RequestBuilder对象,并传入了相关的参数进去,完成了asDrawable()方法调用之后返回来RequestBuilder对象调用load方法:
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
Log.e(TAG, "load: "+string );
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
Log.e(TAG, "loadGeneric: -------load方法调用完成");
this.model = model;
isModelSet = true;
return this;
}
load方法中调用了loadGeneric()方法,loadGeneric()方法中也没有做太多的操作,只是保存了我们的url并且将isModelSet设置为true,意思是model已经设置了。
到此load方法执行完毕了,最终返回了RequestBuilder对象。
接下来将执行into方法了,我们的图片加载以及图片显示的逻辑都是这个方法完成的,由此可知其内部是十分复杂的,接下来我们会单独介绍一下into方法。欢迎点击!
十分感谢各位的阅读,如有大家有什么疑问或者有好的见解,欢迎给我留言,谢谢!