DecodeJob 任务,实现 Runnable 接口,具有状态,关联数据 Fetcher 和回调通知。非内存 Fetcher 时,将该任务分配给合适的线程池 execute(),从 Disk,Res 或 Net 获取。
一、DataFetcherGenerator 流程
1,根据任务运行原因,确定状态Stage和数据生产者Generator。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//初始阶段是Stage.INITIALIZE
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
//异常抛出
}
任务可能多次运行,通过 RunReason 表示此次运行原因。
任务运行原因 包括
INITIALIZE
SWITCH_TO_SOURCE_SERVICE
DECODE_DATA
任务创建时,RunReason初始化INITIALIZE,第一次执行runWrapped()方法,初始化Stage和Generator。
任务二次运行SWITCH_TO_SOURCE_SERVICE,从原始数据源获取数据(如网络),使用前次保存的Stage和Generator。
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
}
}
getNextStage()和getNextGenerator()方法,根据上一步当前Stage,初始化下一个状态,同时根据Stage创建Generator。
六种Stage状态
INITIALIZE, //The initial stage
RESOURCE_CACHE, //Decode from a cached resource.
DATA_CACHE, //Decode from cached source data.
SOURCE
ENCODE
FINISHED
Stage | DataFetcherGenerator | 方式 |
---|---|---|
RESOURCE_CACHE | ResourceCacheGenerator | 资源文件 |
DATA_CACHE | DataCacheGenerator | 缓存 |
SOURCE | SourceGenerator | 原始数据源 |
2,runGenerators()方法,运行Generator。
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
//状态变成SOURCE,退出循环。
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
while循环,执行Generator的startNext()方法,返回失败表示未获取数据,继续下一个阶段和生产者,当需要从原始数据源获取时(即状态SOURCE),退出while循环,reschedule()二次运行任务。
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);//该DecodeJob任务
}
运行理由转换成SWITCH_TO_SOURCE_SERVICE,Callback即EngineJob,向线程池派发同一个任务对象。
@Override
public void reschedule(DecodeJob> job) {
getActiveSourceExecutor().execute(job);
}
再次运行runWrapped()方法,根据RunReason直接执行runGenerators()方法,Generator即前次已获取的SourceGenerator。
二、DataFetcherGenerator 架构
DataSource 数据源
LOCAL ,本地(如 assets )
REMOTE ,远程 (网络)
DATA_DISK_CACHE,本地缓存
RESOURCE_DISK_CACHE ,downsampled 或 transformed 处理过的资源文件
MEMORY_CACHE ,内存
数据 Fetcher
接口 DataFetcher
loadData() 方法,具体 Fetcher 方法。
index | Fetcher | Loader |
---|---|---|
1 | HttpUrlFetcher | HttpGlideUrlLoader |
2 | OkHttpStreamFetcher | OkHttpUrlLoader |
3 | Fetcher | ByteArrayLoader |
4 | ByteBufferFetcher | ByteBufferFileLoader |
5 | DataUriFetcher | DataUrlLoader |
6 | FileFetcher | FileLoader |
7 | FilePathFetcher | MediaStoreFileLoader |
8 | ThumbFetcher | MediaStoreVideoThumbLoader / MediaStoreImageThumbLoader |
9 | UnitFetcher | UnitModelLoader |
10 | FileDescriptorAssetPathFetcher,(AssetPathFetcher) | AssetUriLoader |
11 | StreamAssetPathFetcher,(AssetPathFetcher) | AssetUriLoader |
12 | AssetFileDescriptorLocalUriFetcher,(LocalUriFetcher) | UriLoader |
13 | FileDescriptorLocalUriFetcher,(LocalUriFetcher) | UriLoader |
14 | StreamLocalUriFetcher,(LocalUriFetcher) | UriLoader |
15 | MultiFetcher | MultiModelLoader |
HttpUrlFetcher 和 OkHttpStreamFetcher 的数据源 DataSource 是 REMOTE ,其他都是 LOCAL
MultiFetcher 集成 Fetcher 集合,使用第一项。
根据 model 的 Class 类型,从已注册的 Entry 中,判断标准,model 是 modelClass 本身或子类,由 ModelLoaderFactory 构建支持的 ModelLoader 列表
注册 ModelLoaderRegistry 。
注册的 Model,Data 和 ModelLoaderFactory 。
Model | Data | ModelLoaderFactory |
---|---|---|
int | InputStream | ResourceLoader.StreamFactory |
int | ParcelFileDescriptor | ResourceLoader.FileDescriptorFactory |
int | Uri | ResourceLoader.UriFactory |
int | AssetFileDescriptor | ResourceLoader.AssetFileDescriptorFactory |
String | InputStream | DataUrlLoader.StreamFactory |
String | InputStream | StringLoader.StreamFactory |
String | ParcelFileDescriptor | StringLoader.FileDescriptorFactory |
String | AssetFileDescriptor | StringLoader.AssetFileDescriptorFactory |
File | ByteBuffer | ByteBufferFileLoader.Factory |
File | InputStream | FileLoader.StreamFactory |
File | ParcelFileDescriptor | FileLoader.FileDescriptorFactory |
File | File | UnitModelLoader.Factory |
Uri | InputStream | HttpUriLoader.Factory |
Uri | InputStream | AssetUriLoader.StreamFactory |
Uri | ParcelFileDescriptor | AssetUriLoader.FileDescriptorFactory |
Uri | InputStream | MediaStoreImageThumbLoader.Factory |
Uri | InputStream | MediaStoreVideoThumbLoader.Factory |
Uri | InputStream | UriLoader.StreamFactory |
Uri | ParcelFileDescriptor | UriLoader.FileDescriptorFactory |
Uri | AssetFileDescriptor | UriLoader.AssetFileDescriptorFactory |
Uri | InputStream | UrlUriLoader.StreamFactory |
Uri | File | MediaStoreFileLoader.Factory |
Uri | Uri | UnitModelLoader.Factory |
URL | InputStream | UrlLoader.StreamFactory |
GlideUrl | InputStream | HttpGlideUrlLoader.Factory |
Bitmap | Bitmap | UnitModelLoader.Factory |
GifDecoder | GifDecoder | UnitModelLoader.Factory |
byte[] | ByteBuffer | ByteArrayLoader.ByteBufferFactory |
byte[] | InputStream | ByteArrayLoader.StreamFactory |
Drawable | Drawable | UnitModelLoader.Factory |
根据 model,由 Factory 创建 ModelLoader,handle()过滤,判断该 ModelLoader 是否由特殊model。
例如String类 model,仅生成3个StringLoader,DataUrlLoader 只处理data:image开头的String类型。
三、生产者 SourceGenerator
@Override
public boolean startNext() {
//当已经有了网络数据时,dataToCache不空,存储磁盘缓存中。
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
//内部Disk缓存生产者,当上一步去cacheData成功后,会初始化该对象。
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
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;
}
1,从DecodeHelper类中获取LoadData列表,遍历每一项查找匹配LoadData,调用ModelLoader.LoadData>内部DataFetcher的loadData()方法。如果Source是远程网路,这里即发起网路请求的位置。
2,DataFetcher
远程网络:LoadData是MultiModelLoader,DataFetcher是MultiFetcher,内部有一个DataFetcher列表,用到OkHttpStreamFetcher的loadData()方法。
public void loadData(@NonNull Priority priority,
@NonNull final DataCallback super InputStream> callback) {
Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
for (Map.Entry headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
this.callback = callback;
call = client.newCall(request);
call.enqueue(this);//该类实现okhttp回调
}
通过Okhttp的newCall()方法请求,OkHttpStreamFetcher类实现Okhttp的回调Callback,图片下载完成回调,DataCallback接口,生产者SourceGenerator实现DataCallback接口。
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
//数据保存在内部。
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
当Generator执行到onDataReady回调方法时,如果支持Disk缓存,将源数据持久化,将dataToCache保存在Generator内部。FetcherReadyCallback回调,reschedule()方法,再进行一次任务。不支持Disk缓存,onDataFetcherReady()回复。
3,第一次startNext()方法时,dataToCache是空,内部DataCacheGenerator也是空,二次DecodeJob任务数据源不空时,cacheData()方法,数据Disk缓存,同时引用置空,数据被拦截交DataCacheGenerator处理。
四、生产者 DataCacheGenerator
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//this代表callback
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
1,查找ModelLoader列表,从cacheKeys列表,获取Key,根据Key查找缓存File,缓存存在时,初始化ModelLoader列表,结束循环,列表一直是空时候会循环多次。
2,根据cacheFile,在列表中匹配ModelLoader,创建LoadData。由内部DataFetcher加载数据。
文件读取:ByteBufferFileLoader实现ModelLoader接口,内部ByteBufferFetcher实现DataFetcher接口。
ByteBufferFetcher的loadData()方法,Data类型ByteBuffer。
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
从DataCacheGenerator内部的cacheFile读取ByteBuffer,数据最终交给DecodeJob的onDataFetcherReady()回复。
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
五、Generator Callaback
接口 DataFetcherGenerator.FetcherReadyCallback。
DecodeJob实现,Generator构造方法入参数。
@Override
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;
//当前线程是否和runGenerators方法时的线程相等。
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
TraceCompat.endSection();
}
}
}
调用decodeFromRetrievedData()方法。
private void decodeFromRetrievedData() {
Resource resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
decodeFromData()方法,获取Resource
任重而道远