没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
试读
21页
文章目录准备源码开始阅读1、with()2、load()3、into()总结 众所周知Glide是Android开发中普遍使用的图片加载框架,功能非常强大,API非常简便,也是Google官方唯一推荐的图片加载框架。 基本用法,本文不再叙述,详情请参阅官方Github主页 一般情况下,我们想在界面上显示一张图片,只需要一行代码即可实现。图下所示: Glide.with(this).load(url).into(imageView) 看起来是如此的简洁、完美!但你可能不知道Glide在背后做了多么复杂、繁重的工作,才将图片展示到我们面前。本着知其然也要知其所以然,那么今天我们就来揭开Glide
资源推荐
资源详情
资源评论
Android图片加载框架最新解析:从源码的角度理解图片加载框架最新解析:从源码的角度理解Glide的执的执
行流程行流程
文章目录文章目录准备源码开始阅读1、with()2、load()3、into()总结
众所周知Glide是Android开发中普遍使用的图片加载框架,功能非常强大,API非常简便,也是Google官方唯一推荐的图片加
载框架。
基本用法,本文不再叙述,详情请参阅官方Github主页
一般情况下,我们想在界面上显示一张图片,只需要一行代码即可实现。图下所示:
Glide.with(this).load(url).into(imageView)
看起来是如此的简洁、完美!但你可能不知道Glide在背后做了多么复杂、繁重的工作,才将图片展示到我们面前。本着知其
然也要知其所以然,那么今天我们就来揭开Glide神秘的面纱。
准备源码准备源码
既然要阅读源码,必须先要把源码下载下来,下载有两种方式:
第一种(推荐推荐):如果项目中已经用到Glide,那么就可以用Android Studio 打开项目,点击Glide的引用直接查看。
第二种:在Glide的Github开源主页下载源码,地址:https://github.com/bumptech/glide
这里推荐第一种,因为使用Android Studio阅读可以进行自由的跳转,方便我们阅读。本文是基于最新的Glide 4.11.0来解析
的,随着官方不停的版本迭代,本文也会随着变动不定时更新。读者也可以在下方留言反馈。
开始阅读开始阅读
问:如何把大象装冰箱里?问:如何把大象装冰箱里?
答:总共分三步,第一步,答:总共分三步,第一步,Glide.with(this);第二步,;第二步,load(url);第三步,;第三步,into(imageView)。。
阅读源码的思路是从我们平时使用的语句开始,也就是Glide.with(this)。
在分析的过程中我们不必把源码的每一句都搞懂,那样会把你搞得晕头转向,摸不清思路。因为这些代码都不是一个人写的,
同样的功能有多种解决方法。记住我们只需要分析主要的实现逻辑就可以了。
准备好了吗?现在我们开始!
1、、with()
with()方法是Glide类中的一组静态方法,有多个重载方法,如下所示:
public class Glide implements ComponentCallbacks2 {
...
@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);
}
...
}
可以看到,with()的重载方法非常多,可以传入Context、Activity、Fragment以及View,其中传入其中传入android.app.Fragment的的
方法已经标记为过时,不建议使用了,我们可以传入方法已经标记为过时,不建议使用了,我们可以传入androidx.fragment.app.Fragment来替代。来替代。 每个with()方法中的逻辑都
非常简单,都先是调用getRetriever()静态方法传入Context对象获得一个RequestManagerRetriever对象,然后调用
RequestManagerRetriever的get()方法获取RequestManager“请求管理器”对象。
先看下getRetriever()方法:
public class Glide implements ComponentCallbacks2 {
...
@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();
}
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
...
}
通过get()方法中两次判断glide == null,再加上synchronized(),表明这里是一个单例模式,具体的单例细节我们不必深究。这
里getRetriever()方法中调用get()方法获取Glide单例对象,然后通过Glide对象获取内部的RequestManagerRetriever对
象,RequestManagerRetriever是Glide构造方法中定义的对象。
接下来我们看RequestManagerRetriever的get()方法:
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
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
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, /*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 {
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 {
assertNotDestroyed(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());
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);
}
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
...
}
上述代码有很多的get()重载方法,看起来比较复杂,其实梳理一下还是很简单的。不论传入的是Context,还是Fragment等
等,实际上只有两种情况而已,即传入Application类型的情况和非Application的情况。
有一点需要说明,通过有一点需要说明,通过if (Util.isOnMainThread())判断语句,可以看出,我们如果在非主线程中使用)判断语句,可以看出,我们如果在非主线程中使用Glide,它都会当成传入它都会当成传入
Application的情况来处理。的情况来处理。
先来看传入Application类型的情况。如果在Glide.with()方法中传入Application对象,这里会调用get(context)中的
getApplicationManager(context)方法。如下所示:
public class RequestManagerRetriever implements Handler.Callback {
...
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
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;
}
...
}
由于Glide本身就是和应用程序生命周期同步的,所以这里并不需要做什么特殊处理。应用关闭,Glide加载也会终止。
上面的情况比较简单,我们再来看传非Application的情况。无论传Fragment还是Activity,最终的流程都是向当前的Activity添
加一个隐藏的Fragment。使用这样一个小技巧,这样Glide就可以知道Activity的生命周期了,加载图片时,也会随着Activity的
生命周期,判断是否继续加载。代码如下所示:
public class RequestManagerRetriever implements Handler.Callback {
...
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
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 SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
...
}
supportFragmentGet()中调用了getSupportRequestManagerFragment()方法,添加了一个SupportRequestManagerFragment
,SupportRequestManagerFragment 就是一个Fragment。
到这里,with()的源码比较好理解吧,不过越到后面会越复杂,接下来我们开始分析第二步吧!
2、、load()
我们都知道Glide支持加载图片URL,或是本地路径等多种数据形式的,由于我们不可能把每种都分析一遍,所以这里只选其中之
剩余20页未读,继续阅读
资源评论
weixin_38699757
- 粉丝: 4
- 资源: 1027
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功