不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!
Glide的源码分析
面试题:为什么不能在子线程调用with方法?
答:因为在子线程调用,不会产生一个空白的Fragment和Activity进行生命周期的绑定;可能导致Activity销毁了,图片请求资源仍然存在,导致内存泄漏。
面试题:为什么使用Glide框架需要网络请求权限?
答:如果活动缓存和内存缓存中都没有数据可以返回,并且本地磁盘缓存中也没有,就只能执行最后一个方法,通过网络请求去返回数据,因此在无缓存的情况下,需要进行异步网络请求数据。
Glide的使用
使用Glide
框架非常简单,最基本的就一句话。
Glide.with(MainActivity.this).load(url).into(ImageView);
With方法
With
方法最主要的就是调用get
方法,返回一个RequestManager
对象。- 因为
Activity
最终继承FragmentActivity
,所以传入的参数是FragmentActivity
。
在get方法中,有这么一句。
public RequestManager get(FragmentActivity activity) {
//通过判断是否在子线程
if (Util.isOnBackgroundThread()) {
//位于子线程,直接和Application的context绑定
//就不能和Activity生命周期绑定
return get(activity.getApplicationContext());
} else {
//位于主线程
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
//使用一个空白的Fragment和Activity进行生命周期绑定
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
load方法
- 调用
RequestManager
的load
方法 - 返回一个
RequestBuilder
对象
into方法(重点)
into方法的时序图
- 调用
RequestBuilder
的into
方法
public Target<TranscodeType> into(ImageView view) {
//确定在主线程执行UI操作
Util.assertMainThread();
//确定控件存在
Preconditions.checkNotNull(view);
//是否设置了scaleType属性
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
if (requestOptions.isLocked()) {
//克隆,原型设计模式
requestOptions = requestOptions.clone();
}
//通过scaleType属性判断走哪条路径
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions.optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions.optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
//不设置scaleType属性的默认路径
requestOptions.optionalFitCenter();
break;
case FIT_XY:
requestOptions.optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//最终进入的方法
//这里确定返回的target对象为ImageViewTarget
//铺垫,伏笔
return into(context.buildImageViewTarget(view, transcodeClass));
}
-
into
里面的子线方法——buildImageViewTarget
-
进入
buildImageViewTarget
方法public <X> Target<X> buildImageViewTarget(ImageView imageView, Class<X> transcodeClass) { return imageViewTargetFactory.buildTarget(imageView, transcodeClass); }
通过buildImageViewTarget
的源码可以看出,通过工厂模式,进行Target对象的实例化。
- 继续调用上面的
into
方法
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//上一个请求
Request previous = target.getRequest();
//上一个请求没有结束
if (previous != null) {
//将请求结束,确保下一个请求执行前,所有请求结束
requestManager.clear(target);
}
//lock()保证线程安全
requestOptions.lock();
//得到当前请求,通过buildRequest一层层调用可知,最终返回的是singleRequest对象
//铺垫,伏笔
Request request = buildRequest(target);
//将请求和Target绑定
target.setRequest(request);
//进入这个方法,执行请求
requestManager.track(target, request);
//最终返回这个Target对象,即无论调用路径多长
//最终都会回到这个target对象
return target;
}
铺垫:通过buildRequest
可以知道返回的Request
是SingleRequest
。
- 调用
RequestManager
的trace
方法
void track(Target<?> target, Request request) {
targetTracker.track(target);
//执行这个Request请求
requestTracker.runRequest(request);
}
- 执行请求,调用
RequestTracker
的runRequest
方法
public void runRequest(Request request) {
//运行请求,Set类型
//private final Set<Request> requests
requests.add(request);
if (!isPaused) {
//未暂停,开始执行
request.begin();
} else {
//等待请求,List类型
// private final List<Request> pendingRequests = new ArrayList<>();
pendingRequests.add(request);
}
}
由源码可知,两个请求的类型不同,因为他们的状态不同,一个等待,一个执行。
- 调用
Request
的begin
方法
package com.bumptech.glide.request;
/**
* A request that loads a resource for an {@link com.bumptech.glide.request.target.Target}.
*/
public interface Request {
/**
* Starts an asynchronous load.
*/
void begin();
...
}
通过源码发现,Request为一个接口,那么它的实现类是什么呢?
上述铺垫的buildRequest方法告诉我们,它的实现类是SingleRequest。
- 调用
SingleRequest
的begin
方法
public void begin() {
...
status = Status.WAITING_FOR_SIZE;
//如果Target尺寸和这个一致
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//准备
onSizeReady(overrideWidth, overrideHeight);
} else {
//获得target尺寸
target.getSize(this);
}
...
}
- 调用
SingleRequest
的onSizeReady
方法
public void onSizeReady(int width, int height) {
...
//设置正在运行
status = Status.RUNNING;
...
//调用load方法,加载引擎
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);
...
}
- 调用
Engine
的load
方法
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
...
//key表示引擎的唯一索引
//通过工厂模式创建得到
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//得到引擎资源
//先从内存缓存中找
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
//缓存中有
if (cached != null) {
//直接准备资源
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//活动缓存,面向用户
//逻辑和内存缓存一致
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//看看EngineJob是否存在在磁盘缓存中
EngineJob<?> current = jobs.get(key);
//存在则执行下列操作
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//不存在,通过工厂模式创建
EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool);
//DecodeJob同理
DecodeJob<R> decodeJob = decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
onlyRetrieveFromCache,
options,
engineJob);
//jobs里面没有,加入磁盘中
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//将decodeJob放入engineJob中
//开启引擎
engineJob.start(decodeJob);
...
return new LoadStatus(cb, engineJob);
}
- 调用
EngineJob
的start
方法
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
//最终执行
executor.execute(decodeJob);
}
- 调用
GlideExecutor
的execute
方法(线程池管理执行任务)
@Override
public void execute(Runnable command) {
if (executeSynchronously) {
command.run();
} else {
super.execute(command);
}
}
execute
方法传入的参数是DecodeJob
,在这个方法可知,里面的参数是Runnable
类型的。然后执行Runnable
的run
方法,发现Runnable
是个接口,那么它的具体实现类是什么呢?就是它传入的参数了,是DecodeJob
。
- 调用
DecodeJob
的run
方法
public void run() {
try {
//取消执行
if (isCancelled) {
notifyFailed();
return;
}
//不取消就执行这个方法
runWrapped();
} catch (RuntimeException e) {
...
}
}
- 执行
DecodeJob
的runWrapped
方法
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
//铺垫,是否配置缓存策略
//默认返回source
currentGenerator = getNextGenerator();
//执行
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
//执行
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
getNextGenerator方法中证明了下面的实现类是ResourceCacheGenerator,DataCacheGenerator, SourceGenerator(默认返回)中的。
- 执行
DecodeJob
的runGenerators
方法
private void runGenerators() {
...
while (!isCancelled && currentGenerator != null
//当前Generator的下一个方法
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
...
}
- 调用DataFetcherGenerator的
startNext
方法
发现又是一个接口,因为只有SourceGenerator中有这个方法,所以实现类SourceGenerator。
- 实现类实现
startNext
方法
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//返回loadData
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//去获取数据,返回
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
-
调用loadData.fetcher.loadData,发现又是个接口,这里找不到实现类,那么就要看这个对象如何得到的。
glide
有个注册机制,注册很多的组件,会把HttpGlideUrlLoader
注册进来,进行网络请求。loadData = helper.getLoadData()方法中有
LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
通过注册机制可知:LoadData<?> current = HttpGlideUrlLoader;
-
调用里面的buildLoadData方法,发现是接口方法,然后找到实现类
HttpGlideUrlLoader
。 -
调用
HttpGlideUrlLoader
的buildLoadData
方法
-
到HttpUrlFetcher类,进行网络请求
-
继续loadData,最后到
loadDataWithRedirects
方法,返回InputSream
,得到数据流InputStream
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//得到数据Stream
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//得到的数据回调
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
private InputStream loadDataWithRedirects(
URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
...
//真正的网络请求,底层Socket
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
...
}
- 得到的数据回调,调用onDataReady发现又是接口,数据回调到
DataCacheGenerator
缓存 - 继续回调,又是接口,到
DecodeJob
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
后面的InputStream
回调之后,会在StreamBitmapDecoder
中进行采样压缩,变成bitmap
,然后返回到Enigne
中保存在活动缓存中,最后最后,回调OnResourceReady方法,最后到ImageViewTarget
的OnResourceReady
方法,再通过setDrawable等方法,显示图片。
总结流程(简化)
- 构建Glide
- 给每一个RequestManager绑定一个空白的Fragment管理生命周期
- 构建Request
- 请求之前,判断两级缓存(活动缓存和内存缓存)中是否有需要的数据
- 都没有,建立一个新的异步任务
- 在本地的磁盘缓存中寻找
- 若没有,则进行网络请求返回一个输入流InputStream。
- 将InputStream采样压缩处理变为Bitmap,防止出现oom
- 后将Bitmap转换为drawable
- 传输到终点ImageViewTarget中,并在其子类DrawableImageViewTarget中显示图片。
生命周期绑定的作用
比如当前有100个请求,10个请求正在处理,90个请求正在等待。若这10个请求执行完毕,Activity或者Fragment被销毁,则其他的未执行的请求也一同回收,不会再发送请求。即将所有的资源进行关联,同步回收,避免出现内存泄漏。