Glide Fetcher


DecodeJob 任务,实现 Runnable 接口,具有状态,关联数据 Fetcher 和回调通知。非内存 Fetcher 时,将该任务分配给合适的线程池 execute(),从 Disk,Res 或 Net 获取。

一、DataFetcherGenerator 流程

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 架构

DataFetcherGenerator 架构

DataSource 数据源

LOCAL ,本地(如 assets )
REMOTE ,远程 (网络)
DATA_DISK_CACHE,本地缓存
RESOURCE_DISK_CACHE ,downsampled 或 transformed 处理过的资源文件
MEMORY_CACHE ,内存

数据 Fetcher
接口 DataFetcher<T>,T类型,内部接口,DataCallback 通知结果,参数是 T类型,Exception 失败 。
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<Model,Data>
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<File>
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<Uri>
URL InputStream UrlLoader.StreamFactory
GlideUrl InputStream HttpGlideUrlLoader.Factory
Bitmap Bitmap UnitModelLoader.Factory<Bitmap>
GifDecoder GifDecoder UnitModelLoader.Factory<GifDecoder>
byte[] ByteBuffer ByteArrayLoader.ByteBufferFactory
byte[] InputStream ByteArrayLoader.StreamFactory
Drawable Drawable UnitModelLoader.Factory<Drawable>

根据 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<T>接口,内部DataCallback接口数据加载结果回调,Generator实现。
远程网络: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<String, String> 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<File, ?> 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<R> resource = null;
    try {
        resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
        throwables.add(e);
    }
    if (resource != null) {
        notifyEncodeAndRelease(resource, currentDataSource);
    } else {
        runGenerators();
    }
}

decodeFromData()方法,获取Resource<R>结果,notifyEncodeAndRelease()通知。


任重而道远

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • View#requestLayout解析 requestLayout的本质是通知ViewRootImp请求一次sc...
    gczxbb阅读 3,721评论 0 1
  • 触屏是用户和手机交互的基础,手指触屏时产生一系列事件,控制视图改变,在树形视图中,事件从顶层向下传递。 View和...
    gczxbb阅读 629评论 0 1
  • 转载于:请叫我大苏的 Android屏幕刷新机制 我主要的目的是跟着文章的思路从新走一遍,让自己更好的理解相关的知...
    ghroost阅读 2,177评论 2 11
  • 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享...
    一个不掉头发的开发阅读 11,386评论 12 74
  • 从0到1开始演讲 TED演讲风靡全球,你我都可能看过很多个演讲视频,有时从中获取新的科学知识,有时会被演讲者的机智...
    想做一块石头阅读 233评论 0 0