Glide一个强大的图片加载框架,注重于平滑的滚动,设计简洁易用的API,具有很强大的和扩展性。现在来对他的加载原理进行深入的分析,本文是基于最新版本4.6.1进行分析的。通常情况下Glide的使用如下一行代码就可以搞定。
Glide.with(this).load("url").into(imageView);
就沿着这个思路进行一步一步的分析。
一、with方法
with方法存在于Glide里面,它提供了很多的重载方法,包含Context、Activity、FragmentActivity、Fragment、View五大重载的参数,因此它可以在这五类中使用。with返回的是RequestManager对象,这个对象在后面进一步说明。
public static RequestManager with(Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(View view) {
return getRetriever(view.getContext()).get(view);
}
在上面的getRetriever方法主要是对传递过来的context对象做了一个非空校验,返回RequestManagerRetriever对象,这个类主要是区分传递过来的context是所属Activity或者Fragment等。RequestManagerRetriever中的get方法返回RequestManager对象,RequestManager这个类主要是和当前所在的Activity或者Fragment等进行生命周期绑定。
1、getRetriever方法
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).");
//--a --b
return Glide.get(context).getRequestManagerRetriever();
}
--a、Glide的get方法是一个非常常见的一个双锁校验的单例模式,返回glide实例。
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//--c
checkAndInitializeGlide(context);
}
}
}
return glide;
}
--c、这个checkAndInitializeGlide最终调用的是:
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
...........................省略............................
Glide glide = builder.build(applicationContext);
............................省略...........................
Glide.glide = glide;
}
这个builder.build方法就是创建Glide,GlideBuilder里面主要初始化了一些相关参数,例如:资源线程池,内存缓存线程池,Bitmap线程池、动画池,内存创建,缓存大小以及相关设置等等,为了不偏离主线,这个类再次就不在深入了,后面在介绍。
--b、getRequestManagerRetriever这个没有什么好说的。
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
2、get方法
get方法也有很多重载的方法和with方法类似,不可能全部做分析,这里就以其中的Context作为参数的get方法进行分析,首先是对他做了一个非空校验,然后判断当前的context属于哪个Fragment还是Fragment等,如果都不属于则默认是当前应用的context。
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) {
//获取当前FragmentActivity的RequestManager
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
//获取当前FragmentActivity的RequestManager --a
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
//获取当前FragmentActivity的RequestManager
return get(((ContextWrapper) context).getBaseContext());
}
}
//获取当前整个应用的RequestManager
return getApplicationManager(context);
}
3、Glide和Activity生命周期绑定
以上面的--a为例,根据Activity创建一个fragment用来和Glide生命周期绑定。看下面的注释:
public RequestManager get(@NonNull Activity activity) {
//判断是否在子线程,如果是在子线程则获取整个应用的application,
//否则是在主线程,和当前所在的Activity或者Fragment生命周期绑定,这个是在RequestManager类实现的。
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//判断当前的Activity是否被销毁
assertNotDestroyed(activity);
//获取当前activity的FragmentManager管理类
android.app.FragmentManager fm = activity.getFragmentManager();
//根据当前Activity创建一个fragment用来和Glide生命周期绑定
return fragmentGet(activity, fm, null /*parentHint*/);
}
}
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint) {
//创建一个Fragment --a
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
//根据当前的Fragment得到RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//如果当前的requestManager为空,则获取Glide
Glide glide = Glide.get(context);
/** 创建requestManager(核心)
* 参数一:glide
* 参数二:当前Fragment的ActivityFragmentLifecycle,他实现了Lifecycle接口是一个观察者设计模式,用set存储
* LifecycleListener来观察事件的开始、停止、移除、销毁。该方法的初始化值是在getRequestManagerFragment方法里面
* 请参考--a说明
* 参数三:基于Context的RequestManager上下文环境,请参考--a说明
*/
requestManager =factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//给当前的Fragment设置一个RequestManager
current.setRequestManager(requestManager);
}
return requestManager;
}
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@Override
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
//直接返回RequestManager实例对象,RequestManager中具体的生命周期管理见下面4。
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
--a、getRequestManagerFragment
RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
//通过tag获取当前的Fragment
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//如果获取不到
if (current == null) {
//从存储的Map集合中获取
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
//如果还是没有则说明没有创建过该Fragment,即该Activity或者Fragment是新的页面,之前没有请求过重写创建 --b
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
//存储到Map集合中
pendingRequestManagerFragments.put(fm, current);
//提交
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//发送消息,设置tag
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
--b、RequestManagerFragment
public class RequestManagerFragment extends Fragment {
………………………………………………………………………省略部分代码……………………………………………………………………………………
private static final String TAG = "RMFragment";
public RequestManagerFragment() {
//在此创建ActivityFragmentLifecycle对象,该类实现Lifecycle接口,在该类中创建Set<LifecycleListener>,
//在重写的方法中监听Activity的生命周期回调
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
public RequestManagerTreeNode getRequestManagerTreeNode() {
return requestManagerTreeNode;
}
public RequestManager getRequestManager() {
return requestManager;
}
//在此返回lifecycle,注意这个lifecycle是当前的页面(Activity、Fragment)所属的的lifecycle
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
………………………………………………………………………省略部分代码……………………………………………………………………………………
}
4、RequestManager的构造方法
RequestManager是一个核心类,主要作用是实现图片加载和当前页面的生命周期绑定,便于图片管理,避免了内存泄漏、图片错位等问题,使其更加智能。在上面的Glide和Activity生命周期绑定分析的最后,我们看到RequestManagerRetriever中RequestManagerFactory的build方法直接返回new RequestManager,因此我们从这个构造方法入手。
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,//请求操作类,请求的取消,发起,重试,完成,失败
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
//监控网络连接状态的一个接口
connectivityMonitor =factory.build(context.getApplicationContext(),new RequestManagerConnectivityListener(requestTracker));
//观察Activity或者Fragment的生命周期
if (Util.isOnBackgroundThread()) {
//如果是子线程,则添加监听,post一个Runnable到主线程
mainHandler.post(addSelfToLifecycle);
} else {
//如果是主线程直接添加监听
lifecycle.addListener(this);
}
//添加当前网络变化的监听
lifecycle.addListener(connectivityMonitor);
//设置请求参数配置信息:RequestOptions用于设置Glide的各种参数,例如缓存,圆角,动画,占位图等
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
//在glide中进行注册,把RequestManager添加进List<RequestManager>
glide.registerRequestManager(this);
}
这样通过lifecycle.addListener就绑定了Activity或者Fragment的生命周期,信息被保存在ActivityFragmentLifecycle的Set<LifecycleListener>中,Activity onStart,则Listener.onStart();Activity销毁,则Set销毁。
with总结:
with方法的作用主要是校验传入的参数,判断是当前的参数是Activity、Fragment还是Application,从而创建对应的RequestManager,在RequestManager中创建一个虚拟的Fragment,绑定当前Activity、Fragment或者Application生命周期,使Glide和当前页面生命周期保持一致。
二、load方法
load方法提供了多种重载方式支持file,URL,drawable,bitmap等等。默认都是asDrawable形式,除此之外还额外手动设置asGif,asBitmap。
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
@Override
public RequestBuilder<Drawable> load(@Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
@Override
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
@Override
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
现在以Glide加载URL为例进行分析:
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
1、asDrawable
可以看到有一个asDrawable,除了asDrawable之外Glide支持设置asBitmap、asGif。Glide默认设置为asDrawable,我们来看一下asDrawable方法。
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
到这一步直接返回了RequestBuilder实例,RequestBuilder是一个图片加载和设置图片参数的一个核心类,几乎绝大部分的图片参数都在这里设置,看下面。
2、load
load方法同样存在于RequestBuilder,他有调用loadGeneric方法,初始化一些参数,同样返回RequestBuilder,我们来看这个方法。
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
//初始化url
this.model = model;
//isModelSet表示model已经被初始化值了
isModelSet = true;
return this;
}
load总结:
load方法比较简单,根据传入的参数,创建RequestBuilder对象,初始化一些参数。
三、Glide相关类
1、Glide
Glide实现了ComponentCallbacks2接口,用于设置七种内存模式和值,这些值和图片占用内存的大小和回收标准有关。主要包括以下:
(1)设置和获取图片缓存路径,如果不进行设置,默认缓存在CacheDir的"image_manager_disk_cache"文件夹下面。
(2)获取glide对象。这个glide是通过initializeGlide方法返回如上分析。
(3) Glide的构造方法,构造方法的参数比较多,一共11个例如:Engine,MemoryCache,BitmapPool,requestManagerRetriever,RequestOptions等等,并且在GlideBuilder创建glide对象。
(4)with的重载方法,见上面分析。
(5)内存模式和大小、本地缓存相关设置等。
(6)RequestManager的注册与解绑。
2、GlideBuilder
GlideBuilder是管理Glide,为其初始化和设置默认参数的一个类。和Glide功能类似提供了设置类存大小、磁盘缓存大小、资源池设置等方法,并且提供了一些默认设置,再通过Glide的构造方法,传递到Glide。
public Glide build(@NonNull Context context) {
……………………………………………………省略一些默认对象创建作为参数的代码…………………………………………………
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
3、GlideContext
GlideContext的继承关系GlideContext ——> ContextWrapper ——> Context,可以看出GlideContext最终继承自Context,ContextWrapper主要是对Context的一些方法进行了包装例如MainLooper,Theme,PackageName,CacheDir等等,GlideContext主要是获取一些相关设置和以下主要的两个方法:
//获取设置的动画
public <T> TransitionOptions<?, T> getDefaultTransitionOptions(@NonNull Class<T> transcodeClass) {
TransitionOptions<?, ?> result = defaultTransitionOptions.get(transcodeClass);
if (result == null) {
for (Entry<Class<?>, TransitionOptions<?, ?>> value : defaultTransitionOptions.entrySet()) {
if (value.getKey().isAssignableFrom(transcodeClass)) {
result = value.getValue();
}
}
}
//如果没有设置任何动画,走默认
if (result == null) {
result = DEFAULT_TRANSITION_OPTIONS;
}
return (TransitionOptions<?, T>) result;
}
//load方法内部参数的ViewTarget,详情见上面分析
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
以上就是Glide.with(this).load(url)的流程分析,现在汇总为一个图,如下:
以上就是Glide的with、load方法加载的整体过程,下一篇文章将对into方法进行分析点击打开链接,这篇文章就到此结束!