Glide 源码分析
Posted 安卓开发-顺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glide 源码分析相关的知识,希望对你有一定的参考价值。
前言:
Glide 作为android 图片加载领域最火的一款框架,其背后的源码设计同样精彩,今天就来一探究竟(基于Glide4.11.0版本)。
由于Glide框架的源码非常庞大,我们不会把所有细节分析一遍,本文只分析其核心源码,重点分析其对生命周期的监听和缓存的处理。
目录
我们的分析思路就从最简单的
Glide.with(context).load(url).into(imageView)
开始,来看看其背后的源码到底是怎么样的。
一、with
Glide有6个with的重载方法,返回值都是RequestManager
这6个方法其实可以分为两类:
- 在主线程调用并且传入 Activity、Fragment或者View类型的Context(这种情况Glide会默认创建一个空的Fragment来感应当前Activity的生命周期)
- 在子线程调用或者传入的Context是ApplicationContext(只要在子线程调用,无论传入什么都会装换为ApplicationContext)
下面我们通过看源码来验证:
我们看with(Activity)的情况
@NonNull
public static RequestManager with(@NonNull Activity activity)
return getRetriever(activity).get(activity);
其中 getRetriever返回了一个 RequestManagerRetriever 对象
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable 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 get(context).getRequestManagerRetriever();
我们来看其get方法:
看,虽然传入的是Activity,但是如果不是主线程就转换为ApplicationContext来处理,这样就和with(Application)是一样的,我们先来看这条分支:
继续跟进:
@NonNull
private RequestManager getApplicationManager(@NonNull Context context)
if (this.applicationManager == null)
synchronized(this)
if (this.applicationManager == null)
Glide glide = Glide.get(context.getApplicationContext());
this.applicationManager = this.factory.build(glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
return this.applicationManager;
比较直接,通过工厂模式创建一个 RequestManager 对象返回就结束了。
然后我们重点来看第二条分支的情况(主线程+Activity、Fragment、或者View)
跟进到fragmentGet,通过方法名可以看出,这里面会构造一个Fragment
/** @deprecated */
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible)
//重点代码,这里会创建出RequestManagerFragment
RequestManagerFragment current = this.getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null)
Glide glide = Glide.get(context);
requestManager = this.factory.build(glide, current.getGlideLifecycle(),
current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
return requestManager;
继续跟进fragmentGet方法的第一行代码:
this.getRequestManagerFragment(fm, parentHint, isParentVisible);
package com.bumptech.glide.manager;
public class RequestManagerRetriever implements Callback
...
@NonNull
private RequestManagerFragment getRequestManagerFragment(@NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible)
//第一步 先通过Tag找下当前是否已经有构造好的Fragment
RequestManagerFragment current = (RequestManagerFragment)fm.findFragmentByTag("com.bumptech.glide.manager");
if (current == null)
//第二步 如果第一步找不到 在从缓存里找下
current = (RequestManagerFragment)this.pendingRequestManagerFragments.get(fm);
if (current == null)
//第三步 缓存里也没有 就创建一个
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible)
current.getGlideLifecycle().onStart();
//放入缓存 避免重复创建,此时再调用此方法就能从缓存直接拿到了
this.pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, "com.bumptech.glide.manager").commitAllowingStateLoss();
//发handler去移除缓存里的fragment,当此handler消息被执行时,通过
//fm.findFragmentByTag已经可以获取到当前fragment了
//注意,这里必须是发handler 不能直接从缓存移除
//因为fragment的加载也是通过handler消息来驱动的,这里牵扯到handler消息机制的原理,简单理解就是handler消息是排队被处理的,下面发的handler消息排在处理fragment消息的后面
this.handler.obtainMessage(1, fm).sendToTarget();
return current;
注释里写的比较清楚了,先通过fm.findFragmentByTag来获取,没有就从缓存取,在没有就创建出RequestManagerFragment。
这里面有个细节就是作者设计了一个缓存pendingRequestManagerFragments(就是一个Map)来防止fragment重复创建,其中从缓存中移除fragment的时机涉及到了fragment的加载原理(handler驱动),和handler机制的原理,如果对二者不熟悉,可能不太容易理解。
注释里面我也给出了详细的解释,如还不能理解请先看下Fragment、Handler相关源码。
现在Fragment有了,那是如何做到感应当前Activity生命周期的呢?
我们来看下RequestManagerFragment的源码:
二、load
三、into
以上是关于Glide 源码分析的主要内容,如果未能解决你的问题,请参考以下文章