Glide源码剖析-with

本篇将分析源码Glide.with()方法

Glide源码剖析-with

将分析源码Glide.with()

在大多数情况下,我们使用Glide进行图片加载无非就是下面一句话

1
2
#Activity
Glide.with(this).load(src).into(imageView)

可以见得Glide帮我们在背后完成了海量的操作,所以下面我们将先按照使用者的角度来进行剖析

with()

1
Glide.with(this)

with()Glide中的一组静态方法。为什么说是一组呢,因为它有很多个重载方法。在我们日常使用中,我们经常性的会往with()里传递Activity,有时也会传递Fragment。所以Glide.with()是一组静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#Glide
...
@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);
}

@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);
}
...

上述代码是精简过之后的代码。可以见得虽然往里面传递了不同的参数,但最终都还是指向了getRetriever().get(),那接下来就先看看getRetriever()是个什么方法把

getRetriever()

1
2
3
4
5
6
7
8
9
10
11
12
#Glide
@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();
}

getRetriever()的代码不多。我们可以简单分析以下

  1. Preconditions.checkNotNull()

    Preconditions.checkNotNull():就是个判空处理,它接收2个参数。第一个就是需要判空的对象,第二个则是如果为空则会抛出的异常信息

    • 使用优势
      1. 节省时间
      2. 简单使用,如果全部手写,可能需要写十几处判空的逻辑,还要处理异常
      3. 适用于空指针异常处理
  2. Glide.get().getRequestManagerRetriever()

    这里可以看出先调用了Glide.get()在调用getRequestManagerRetriever()获取RequestManagerRetriever对象。那么就先看一下Glide.get()方法把

    Glide.get()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #Glide
    @NonNull
    // Double checked locking is safe here.
    @SuppressWarnings("GuardedBy")
    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;
    }

    就是单例模式下获取本身。至于是如何进行构造的我们先不用理会,这里就只用明白就是获取一个自己出来即可

    那剩下的就只有getRequestManagerRetriever()了

    getRequestManagerRetriever()
    1
    2
    3
    4
    5
    6
    7
    #Glide
    private final RequestManagerRetriever requestManagerRetriever;
    ...
    @NonNull
    public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
    }

    代码啥也没做,就是返回了个RequestManagerRetriever回来。至于它是在哪被初始化的,我们先也不展开了

回到Glide.with()我们梳理一遍,with()内部先调用了getRetriever()去获取RequestManagerRetriever,在调用了.get()方法,相当于是直接调用了RequestManagerRetriever.get()方法。所以说最终还是调用的是RequestManagerRetriever.get()方法

那我们也就只能继续去查看RequestManagerRetriever.get()方法了

RequestManagerRetriever

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#RequestManagerRetriever
...
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
// 判断是否在主线程、判断context是否是Application
} 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
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}

return getApplicationManager(context);
}
...

我们一个一个分析

  1. 方法一开始就先进行了判空处理

  2. 之后会判断当前是否处于主线程中和传入进来的context是否是Application

    • 如果任意一个条件不满足,则会直接调用getApplicationManager()
  3. 接下就只有三种情况:

    • 第一种就是传入进来的context是FragmentActivity,那么会返回get((FragmentActivity) context)
    • 第二种就是传入进来的context是Activity,那么会返回get((Activity) context)
    • 最后一种就是传入进来的context是属于ContextWrapper,那么会返回get(((ContextWrapper) context).getBaseContext())

    ContextWrapper是继承于Context,而Activity、Service、Application也都是ContextWrapper的直接或间接子类

所以说RequestManagerRetriever.get()方法会根据传递进来的context类型来返回不同的RequestManager,那就继续看看get()方法把

get()

这里就先以参数为FragmentActivity作为例子,别的都大同小异

1
2
3
4
5
6
7
8
9
10
11
12
13
#RequestManagerRetriever
...
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {// 判断是否处于子线程中
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);// 判断传入的Activity是否被销毁
frameWaiter.registerSelf(activity);
FragmentManager fm = activity.getSupportFragmentManager();// 获取activity的FragmentManager
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
  1. 一开始就直接判断当前是否处于后台线程,是的话就直接返回get(activity.getApplicationContext())

    1
    2
    3
    if (Util.isOnBackgroundThread()) {
    return get(activity.getApplicationContext());
    }

    Util.isOnBackgroundThread():判断当前线程是否是后台线程,是返回true,不是返回false

  2. 判断传入进来的activity是否已经被销毁

    1
    assertNotDestroyed(activity);
    assertNotDestroyed
    1
    2
    3
    4
    5
    6
    7
    #RequestManagerRetriever
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private static void assertNotDestroyed(@NonNull Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
    throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
    }
    }

    就判断一下当前的SDK是否大于等于17和传入进来的activity是否被销毁

    Build.VERSION_CODES.JELLY_BEAN_MR1:API 17

  3. 获取当前传入activityFragmentManager

    1
    FragmentManager fm = activity.getSupportFragmentManager();
  4. 最后调用supportFragmentGet(),返回RequestManager出去。😔还是得继续看下去,看看是如何返回RequestManager

RequestManager

这里就是重头戏了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#RequestManagerRetriever
@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);
// This is a bit of hack, we're going to start the RequestManager, but not the
// corresponding Lifecycle. It's safe to start the RequestManager, but starting the
// Lifecycle might trigger memory leaks. See b/154405040
if (isParentVisible) {
requestManager.onStart();
}
current.setRequestManager(requestManager);
}
return requestManager;
}
  1. 首先第八行获取了一个SupporRequestManagerFragment,这其实是一个隐形的Fragment

    1
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);

    通过参数FragmentManager和Fragment(可空)来创建一个隐形的Fragment

    这里创建一个隐形的Fragment的意图就是,想通过添加一个隐形的Fragment到Activity中去,来监听Fragment的生命周期,便于控制加载

    因为Fragment的生命周期是跟随着Activity的,所以可以根据这个方法来监听到Activity的生命周期

  2. 下面又通过刚获取的Fragment又获取到了RequestManager

    1
    RequestManager requestManager = current.getRequestManager();

    RequestManager:其实就是一个生命周期管理类,用来判断当前的生命周期来选择是否继续加载图片

    到这里为止,Glide就可以根据这个 Fragment 的生命周期进行请求管理了。

  3. 但是如果是第一次,那么获取到的RequestManager会为空,就需要继续判空处理,如果刚刚current.getRequestManager()获取为空,则重新创建一个RequsetManager

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    if (requestManager == null) {
    // Factor out this Glide.get() call.
    Glide glide = Glide.get(context);
    // 这有点小技巧,我们要启动RequestManager,但不是
    // 相应的生命周期。 启动RequestManager是安全的,但是启动
    // 生命周期可能会触发内存泄漏
    requestManager =
    factory.build(
    glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    if (isParentVisible) {
    requestManager.onStart();
    }
    // 将创建好的requestManager添加到SupportRequestManagerFragment 上去
    current.setRequestManager(requestManager);
    }

    上述代码中,又重新获取了一次Glide单例,并通过Fractory工厂类来构建RequestManager,构建需要三个参数

    1. Glide实例
    2. 这里的 current.getGlideLifecycle() 就是getSupportRequestManagerFragment中实例化的 ActivityFragmentLifecycle。这样 RequestManager 就与 ActivityFragmentLifecycle 进行了关联
    3. Context

    创建完RequestManager之后,就根据传递进来的isParentVisible来通知requestManager是否开始

    isParentVisible:字面意思就是之前传递进来的Fragment Activity是否显示

    最后就是将 RequestManager 设置到 SupportRequestManagerFragment

    1
    current.setRequestManager(requestManager);

getApplicationContext()

接下来在看一个Application的情况,因为大体上就可以分为两种,context是Application和context不是Application

先放出代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#RequestManagerRetriever
@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) {
// 通常,暂停/恢复是由我们添加到片段或活动的片段来处理的。 然而,在这种情况下,由于附加到应用程序的管理器将不会接收生命周期事件,我们必须强制管理器使用ApplicationLifecycle开始恢复。
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}

return applicationManager;
}

总体上于非Application的差不了多少,不过我们也还是继续分析

  1. 还是和之前一样,先使用传递进来的context去获取到Glide,然后通过Glide去创建Request Manager

  2. 只不过在getApplicationManager()这里,通过Factory创建Request Manager的参数可不一样。在这里第一个参数还是Glide,但是第二个参数就变成了ApplicationLifecycle(),之前是传入Fragment的getGlideLifecycle()也就是Fragment的生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class ApplicationLifecycle implements Lifecycle {
    @Override
    public void addListener(@NonNull LifecycleListener listener) {
    listener.onStart();
    }

    @Override
    public void removeListener(@NonNull LifecycleListener listener) {
    // Do nothing.
    }
    }

    可以看出ApplicationLifecycle是空实现,也就是说这里没有专门做生命周期的处理, 因为 Application 对象的生命周期即为应用程序的生命周期,所以在这里图片请求的生命周期是和应用程序同步的。

总结

所以说,Glide.with()就是根据传递进来的context是什么它就会返回什么样的Request Manager出去,至于Request Manager内部就是创建了一个隐形的Fragment上去,通过这个隐形的Fragment来监听Activity的生命周期变化

也可以说是Glide为了能够自动的配合生命周期来控制图片的加载和暂停,所以才想出判断传入进来的Context是否是Application来考虑是通过一个隐形的Fragment来感知Activity的生命周期还是直接使用ApplicationLifecycle