Glide详解之架构分析

Glide是BumpTech开发的一个同时可支持图片、GIF以及视频加载的Android开源库,同时Glide支持任何用户自定义的网络栈,其主要有以下几个特点:

  • 支持GIF格式动画的解码;
  • 支持本地视频加载解码;
  • 加载大图之前,可预先加载一个小图片
  • 自动管理资源加载请求的生命周期;
  • 给定图片尺寸,可以对资源进行自由转换

Github:https://github.com/bumptech/glide

这里就来分析下Glide的具体架构以及介绍其主要特点,分如下几个方面:

  • Glide代码架构及工作原理;
  • Glide如何自动管理资源加载请求的生命周期的?
  • Glide是如何进行图片的加载与转换的?

架构及工作原理

先来看一下Glide的代码结构,这里主要看下几个核心的包:

  • com.bumptech.glide: 主要负责Glide的初始化,参数配置,Request的创建;
  • com.bumptech.glide.load: 主要负责资源的加载,解码与格式转换;
  • com.bumptech.glide.manager: 负责Glide请求生命周期的自动管理;
  • com.bumptech.glide.module: 用于加载解析用户自定义的网络模块;
  • com.bumptech.glide.provider: 管理Glide中图片、GIF等资源的加载与转换器;
  • com.bumptech.glide.request : 资源加载请求相关以及动画;
  • com.bumptech.glide.util : 常用工具类;

下图是Glide的原理简图。可以看到,Glide大致可以分为五个部分:

  • Glide: 初始化系统,负责管理系统其他模块如数据加载器、网络栈等初始化管理;
  • RequestManager: 创建、初始化以及管理系统所有的Request;
  • Engine: 将资源加载请求放入执行线程池,加载完后返回给主线程;
  • ExecutorService: 线程池执行服务,负责分发调度EngineRunnable可执行对象;
  • DataFetcher: 从磁盘或者网络端加载数据

关于Glide资源加载的详细过程请参考我的另一篇文章:Glide图片加载过程分析

接下来就来看一看,Glide的两个特征:请求生命周期的自动化管理以及系统的泛型化。

如何自动进行生命周期管理

Glide从3.0开始支持Request生命周期的自动管理,即随着Activity或者Fragment的生命周期自动启动、恢复或者停止Request。Glide提供了两种生命周期管理策略:ApplicationLifecycleActivityFragmentLifecycle,前者确保Request的生命周期与APP的Application的生命周期保持一致;而后者则使Request的生命周期与Activity或者Fragment保持一致。

那么,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

class ActivityFragmentLifecycle implements Lifecycle {

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

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

}

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();
}
}
}

在初始化RequestManager时,会根据传入的Context来构造RequestManager(这里假定这里是一个FragmentActivity):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

public RequestManager get(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) {
return get(((ContextWrapper) context).getBaseContext());
}
}
// 返回一个与`ApplicationLifeCycle`对应的RequestManager
return getApplicationManager(context);
}

生成一个无UI的SupportRequestManagerFragment,并将其中的ActivityFragmentLifecycle作为构造函数的参数传递给RequestManager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}

// SupportRequestManagerFragment是一个无UI的Fragment,用于控制Request的生命周期
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}

RequestManager构造时,会将RequestManager作为上述Fragment生命周期的监听者,从而使得RequsetManager中的Request生命周期始终与Fragment保持一致:

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

RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();

ConnectivityMonitor connectivityMonitor = factory.build(context,
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()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
lifecycle.addListener(RequestManager.this);
}
});
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
}

这样,不难看出这样一个生命周期事件的通知链:

1
2

SupportRequestManagerFragment --> ActivityFragmentLifecycle --> RequestMananger

系统的泛型化

Glide在设计上尽可能保持抽象与泛型化,从最大程度上保持了系统的可扩展性与可维护性。这些泛型化主要体现在如下几个方面:

  • 用户加载资源的来源可能是一个包含了URI路径的字符串,可能是一个文件,可能是一个URL,因此需要对资源加载的类型泛型化成一个类ModelLoader<T,Y>(称之为ModelType);
  • 资源的数据类型可能是InputStream,也可以是字节流数组byte[],还可以是一个文件File,因此需要对数据类型进行泛型化成一个类DataFetcher<Y>(称之为DataType);
  • 加载完的资源类型可能是一个drawable,也可能是一个gif文件;可能是一个bitmap,也可能是一个byte[]字节数组,同样将其泛型化成一个类Resource<Z>(称之为ResourceType,实际上是对加载完后的资源的一个包装类型);
  • 不同资源类型可能需要进行转换,比如讲bitmap转换成字节数组byte[];将drawable变换成bitmap,因此可以将这种转换的关系泛化成一个类ResourceTranscoder<Z,R>(TranscodeType);

接下来就来看下这几个泛型类的实现。

ModelLoader

ModelLoader的功能是将资源加载到一个具体的数据类型,比如InputStream中,实际是利用DataFetcher来实现资源的加载。Glide提供了多种类型的ModelLoader将不同资源的文件加载到一个InputStream中去:

  • HttpUrlGlideUrlLoader:将一个GlideUrl加载后到一个Inpustream中;
  • StreamByteArrayLoader: 将一个字节流加载到一个InputStream;
  • StreamFileLoader: 将文件加载到一个InputStream;
  • StreamUrlLoader: 将一个URL资源加载到InputStream;
  • StreamResourceLoader:讲一个Android资源文件加载到InputStream;

DataFetcher

DataFetcher用于从文件或者网络上加载资源,将其变成一个特定的数据类型:

  • HttpUrlFetcher: 获取一个URL资源的InputStream;
  • ByteArrayFetcher: 将一个字节流数据变成InputStream输入流;
  • StreamLocalUriFetcher: 获取本地URI资源的InputStream;
1
2
3
4
5

public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
....
}

ResourceTranscoder

将一种资源类型Resource<Z>转换成另一种类型Resource<R>,比如Bitmap转换成Drawable:

  • BitmapBytesTranscoder: 将bitmap转码成一个字节数组;
  • BitmapToGlideDrawableTranscoder: 将一个bitmap转码成一个GlideDrawable;
  • GifDrawableBytesTranscoder: 将GIF文件转码成字节数组;

有关Glide加载图片的过程以及泛型参数的擦除请参考另一篇文章Glide图片加载过程分析

Glide源码地址