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()通知。


任重而道远

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

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