Glide系列之——初识Glide

前言

Glide是一个优秀的开源图片加载组件,广泛应用在各大App当中,并且也是Google官方强力推荐的一个图片加载库,根据官方文档介绍

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

可以看出,Glide功能是非常强大的。这么优秀的开源组件,肯定是非常值得学习的。

本系列主要是分为以下几个部分:

1、Glide系列之——初识Glide

2、Glide系列之——Glide对象创建及功能扩展

3、Glide系列之——Glide的Request执行流程及回调

4、Glide系列之——Glide缓存机制

5、Glide系列之——图片变换功能Transformation

这篇文章为第一篇:Glide系列之——初识Glide

接入及使用

首先我们来看下Glide的接入以及使用方式,接入方式也比较简单,通过gradle引入即可:

1
2
3
4
5
6
7
8
9
repositories {
google()
jcenter()
}

dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}

Glide最吸引人的莫过于其使用方式了:

1
2
3
4
5
6
Glide.with(this)
.load("http://goo.gl/gEgYUd")
.centerCrop() //centerCrop缩放模式
.circleCrop() //裁剪为圆形
.placeholder(ColorDrawable(Color.RED)) //占位drawable
.into(img);

使用链式调用的方式,使用起来非常方便简洁。短短这几行代码的背后,glide做了大量的工作,因此glide代码量也是相当多的,在进行源码分析的时候只会对整个框架流程进行分析,不会涉及到具体代码细节的分析,感兴趣的同学可以把源码下载下来进行仔细研读

接下来分析一下Glide.with方法里面做了一些什么事情

Glide.with

可以看出,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
@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);
}

可以传入FragmentActivity、Activity、Context、Fragment以及View,然后都会调用getRetriever(@Nullable Context context)来获取到一个RequestManagerRetriever对象:

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

Glide.get(context)方法用于获取Glide对象,Glide是一个单例,全局只有一个,由于构造Glide对象比较复杂,在后续的文章中会进行详细分析。

RequestManagerRetriever

获取到RequestManagerRetriever之后,就会调用其get方法返回一个RequestManager,同样
RequestManagerRetriever.get方法也是有很多重载方法的,也是可以传入FragmentActivity、Activity、Context、Fragment以及View参数的,我们来挑一个复杂点的:
public RequestManager get(@NonNull View view)来看下:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@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());
}

// Support Fragments.
// Although the user might have non-support Fragments attached to FragmentActivity, searching
// for non-support Fragments is so expensive pre O and that should be rare enough that we
// prefer to just fall back to the Activity directly.
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);
}

@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
// 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、如果是子线程,会调用get(context)方法,最终会调用getApplicationManager(context)方法

2、然后会进行View以及View.geContext()的合法性检查,不合法就会抛出异常。不过这里写的有点问题:如果view.getContext()返回null的话,那么在第一步就会crash了,这里是不是可以提一个issue了 ^_^

3、接下来会通过view.getContext找到对应的Activity,如果找不到对应的Activity,同样也是走getApplicationManager(context)逻辑。这里通过context找activity是我们日常开发中经常会遇到的问题,可以学习一下实现方式:

1
2
3
4
5
6
7
8
9
10
@Nullable
private static Activity findActivity(@NonNull Context context) {
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return findActivity(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}

4、如果acivity属于FragmentAcivity类型,就会找到对应的supportFragment。在这段代码上有一段注释,大概意思是:尽管会有非support类型的Fragment会在FragmentActivity上面,但是找non-support Fragments 非常耗时且这种case非常少,因此就直接使用FragmentActivity进行判断了。如果找到的support fragment不为空,就会调用get(fragment)方法,否则调用get(fragmentActivity)方法

5、如果activty不属于FragmentActivity类型,就会走non-support Fragment逻辑

接下来我们来看下get(support fragment)方法:

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

可以看出,如果是主线程,会走supportFragmentGet方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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;
}

在这个方法里面,会通过getSupportRequestManagerFragment方法创建一个SupportRequestManagerFragment,然后里面会有一个RequestManager对象,如果这个RequestManager对象为null,会通过factory新建一个RequestManager然后塞给这个SupportRequestManagerFragment。注意一下,在通过factory创建RequestManager的时候,传入一个参数类型为:ActivityFragmentLifecycle,并且是从SupportRequestManagerFragment里面获取的,说明SupportRequestManagerFragment里面持有了一个ActivityFragmentLifecycle对象,根据这个名字大概可以猜出来是跟生命周期相关的。

在Glide官方文档里面也说了,Glide会自动感应页面的生命周期,在页面pause和resume的时候会自动起停load任务。

那么大概就可以看出RequestManager里面会通过这个ActivityFragmentLifecycle来感应生命周期的变化,而由于SupportRequestManagerFragment持有ActivityFragmentLifecycle对象,因此整个生命周期回调链路应该就是:

SupportRequestManagerFragment -> ActivityFragmentLifecycle -> RequestManager

接下来我们来看下ActivityFragmentLifecycle:

ActivityFragmentLifecycle

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;

@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);

if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}

@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}

void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}

void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}

void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}

public interface Lifecycle {
void addListener(@NonNull LifecycleListener listener);
void removeListener(@NonNull LifecycleListener listener);
}

public interface LifecycleListener {

void onStart();

void onStop();

void onDestroy();
}

可以看出ActivityFragmentLifecycle实现了一个Lifecycle接口,里面有addListener以及removeListener两个方法用于添加LifecycleListener接口,在ActivityFragmentLifecycle里面还有onStart、onStop以及onDestory方法,这些方法应该是供SupportRequestManagerFragment调用的。接下来看下SupportRequestManagerFragment的代码:

SupportRequestManagerFragment

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle lifecycle;

@Nullable private RequestManager requestManager;

public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}

@VisibleForTesting
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}

/**
* Sets the current {@link com.bumptech.glide.RequestManager}.
*
* @param requestManager The manager to put.
*/
public void setRequestManager(@Nullable RequestManager requestManager) {
this.requestManager = requestManager;
}

@NonNull
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}

/** Returns the current {@link com.bumptech.glide.RequestManager} or null if none is put. */
@Nullable
public RequestManager getRequestManager() {
return requestManager;
}

//............

@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}

@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}

@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
//.............

可以看出在SupportRequestManagerFragment的生命周期方法里面会自动调用ActivityFragmentLifecycle对应的方法。

以上分析了fragment生命周期感应的执行流程。既然是生命周期监听,肯定是有地方会调用Lifecycle的addListener方法来监听页面生命周期,由于RequestManager创建的时候传入了Lifecycle,因此接下来看下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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public RequestManager(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode treeNode,
@NonNull Context context) {
this(
glide,
lifecycle,
treeNode,
new RequestTracker(),
glide.getConnectivityMonitorFactory(),
context);
}

// Our usage is safe here.
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
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));

// If we're the application level request manager, we may be created on a background thread.
// In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
// issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
// This should be entirely safe.
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);

defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

glide.registerRequestManager(this);
}

在构造方法里面会先lifecycle.addListener(this)注册生命周期监听,来看下监听回调里面干啥了:

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
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}

@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}

@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}

可以看出在onStart的时候Glide会自动重启request,然后在onStop的时候会自动暂停request,以及在onDestory里面会进行一些清理操作。

ConnectivityMonitor

在构造函数里面同时注册了一个ConnectivityMonitor网络变化监听器,这个网络变化监听器是用来干嘛的呢?来看下其实现类DefaultConnectivityMonitor:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
final class DefaultConnectivityMonitor implements ConnectivityMonitor {
private static final String TAG = "ConnectivityMonitor";
private final Context context;

@SuppressWarnings("WeakerAccess")
@Synthetic
final ConnectivityListener listener;

@SuppressWarnings("WeakerAccess")
@Synthetic
boolean isConnected;

private boolean isRegistered;

private final BroadcastReceiver connectivityReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(@NonNull Context context, Intent intent) {
boolean wasConnected = isConnected;
isConnected = isConnected(context);
if (wasConnected != isConnected) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "connectivity changed, isConnected: " + isConnected);
}

listener.onConnectivityChanged(isConnected);
}
}
};

DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) {
this.context = context.getApplicationContext();
this.listener = listener;
}

private void register() {
if (isRegistered) {
return;
}

// Initialize isConnected.
isConnected = isConnected(context);
try {
// See #1405
context.registerReceiver(
connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
isRegistered = true;
} catch (SecurityException e) {
// See #1417, registering the receiver can throw SecurityException.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to register", e);
}
}
}

private void unregister() {
if (!isRegistered) {
return;
}

context.unregisterReceiver(connectivityReceiver);
isRegistered = false;
}

@SuppressWarnings("WeakerAccess")
@Synthetic
// Permissions are checked in the factory instead.
@SuppressLint("MissingPermission")
boolean isConnected(@NonNull Context context) {
ConnectivityManager connectivityManager =
Preconditions.checkNotNull(
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
NetworkInfo networkInfo;
try {
networkInfo = connectivityManager.getActiveNetworkInfo();
} catch (RuntimeException e) {
// #1405 shows that this throws a SecurityException.
// b/70869360 shows that this throws NullPointerException on APIs 22, 23, and 24.
// b/70869360 also shows that this throws RuntimeException on API 24 and 25.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e);
}
// Default to true;
return true;
}
return networkInfo != null && networkInfo.isConnected();
}

@Override
public void onStart() {
register();
}

@Override
public void onStop() {
unregister();
}

@Override
public void onDestroy() {
// Do nothing.
}

可以看出其主要做的事情是在onStart的时候会注册一个广播,当网络状态发生改变的时候会通过ConnectivityListener接口通知出去,然后在onStop的时候会反注册广播。来看下ConnectivityListener接口的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private class RequestManagerConnectivityListener
implements ConnectivityMonitor.ConnectivityListener {
@GuardedBy("RequestManager.this")
private final RequestTracker requestTracker;

RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
this.requestTracker = requestTracker;
}

@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
synchronized (RequestManager.this) {
requestTracker.restartRequests();
}
}
}
}

可以看出这里做了一件事情:当网络重新链接上的时候会自动重启request来加载图片。

可以看出Glide里面对页面的生命周期以及网络变化均进行了自动监听,不需要业务接入方再做额外的逻辑,这个也是Glide组件相比于其他图片组件的优势之一。这种思想非常值得借鉴,可以用于我们的日常开发当中。关于生命周期自动监听,MVVM框架中LiveData就是使用这一思想来避免内存泄漏问题及实现LifecycleOwner变成active自动实现observer的notify功能。

到这里,我们就获取到了一个RequestManager对象,接下来看下load方法:

RequestManager.load

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
34
35
36
37
38
interface ModelTypes<T> {
@NonNull
@CheckResult
T load(@Nullable Bitmap bitmap);

@NonNull
@CheckResult
T load(@Nullable Drawable drawable);

@NonNull
@CheckResult
T load(@Nullable String string);

@NonNull
@CheckResult
T load(@Nullable Uri uri);

@NonNull
@CheckResult
T load(@Nullable File file);

@NonNull
@CheckResult
T load(@RawRes @DrawableRes @Nullable Integer resourceId);

@Deprecated
@CheckResult
T load(@Nullable URL url);

@NonNull
@CheckResult
T load(@Nullable byte[] model);

@NonNull
@CheckResult
@SuppressWarnings("unchecked")
T load(@Nullable Object model);
}

可以看出load方法是有很多重载方法的,可以加载各种资源类型,这里来看下load(String string)方法:

1
2
3
4
5
6
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}

load方法会先调用asDrawable方法,在RequestManager里面还有两个类似的方法asBitmap以及asGif,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@NonNull
@CheckResult
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}

@NonNull
@CheckResult
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}

@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}

@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}

可以看出as方法里面会生成一个RequestBuilder对象,这个resourceClass代表最终需要传给com.bumptech.glide.request.target.Target的资源类型,是Bitmap、Drawable以及GifDrawable里面的一种。关于这个Target,后续的文章会进行讲解。

RequestBuilder.load

调用RequestManager的asDrawable得到RequestBuilder之后,会调用RequestBuilder的load方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}

load方法里面主要是把传入的url给保存起来

RequestBuider.into

分析到这,我们再来回顾一下最开始我们使用Glide加载图片的代码:

1
2
3
4
5
6
Glide.with(this)
.load("http://i.gtimg.cn/qqlive/images/20191209/i1575881814_1.jpg")
.centerCrop()
.circleCrop()
.placeholder(ColorDrawable(Color.RED))
.into(img);

可以看出调用load之后,接下来会调用RequestBuilder的centerCrop和circleCrop方法,这两个是Transformation,用于设置缩放模式以及裁切为圆形,关于Transformation后续会单独讲解。

设置了Transformation之后,通过placeHolder设置一个占位的drawable,然后into方法传入ImageView,接下来看下into方法:

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
34
35
36
37
38
39
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);

BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}

return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}

可以看出into方法必须运行在主线程,然后如果没有设置过Transformation,会根据ImageView的缩放类型设置对应的Transformation,然后调用下面的into方法开始执行图片加载:

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
34
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}

Request request = buildRequest(target, targetListener, options, callbackExecutor);

Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}

requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);

return target;
}

可以看出,首先会创建一个Request对象,最后通过requestManager.track(target, request)发起request请求加载图片。

到此,这篇文章就接近尾声了,总结一下:

总结

这篇文章主要讲了一下Glide的使用方式、Glide生命周期及网络变化自动化监听处理,对Glide的with、load以及into方法进行了初步的分析。通过这篇文章相信大家对Glide应该有了一个整体的认识,欢迎继续学习:Glide系列之——Glide对象创建及功能扩展

本篇文章到此就结束了,感谢耐心阅读,不对之处,敬请指出~