美文网首页
Glide源码分析-加载任务

Glide源码分析-加载任务

作者: gczxbb | 来源:发表于2018-07-10 11:46 被阅读22次

DecodeJob任务

该任务获取图片,可以从资源中,文件缓存,或者网络中获取。下面看一下它的run方法。

public void run() {
    TraceCompat.beginSection("DecodeJob#run");
    DataFetcher<?> localFetcher = currentFetcher;
    try {
        if (isCancelled) {
            notifyFailed();
            return;
        }
        runWrapped();
    } catch (Throwable t) {
        if (stage != Stage.ENCODE) {
            throwables.add(t);
            notifyFailed();
        }
        if (!isCancelled) {
            throw t;
        }
    } finally {
        if (localFetcher != null) {
            localFetcher.cleanup();
        }
        TraceCompat.endSection();
    }
}

该任务的run方法,调用内部的核心方法runWrapped。在这个方法中,将决定从哪个地方获取图片。

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,所以,在第一次执行该任务时,会走INITIALIZE的分支,获取到阶段和生产者,然后运行生产者。

private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
            && !(isStarted = currentGenerator.startNext())) {
        stage = getNextStage(stage);
        currentGenerator = getNextGenerator();

        if (stage == Stage.SOURCE) {
            reschedule();
            return;
        }
    }
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
        notifyFailed();
    }
}

在while循环中,获取Generator生产者,然后调用它的startNext方法,如果返回标志是false,继续循环获取下一个生产者。
Stage阶段获取,阶段有六个。

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:
    }
}

Generator生产者,根据当前阶段Stage获取,Stage和Generator的对应关系。

Stage Generator
RESOURCE_CACHE ResourceCacheGenerator。
DATA_CACHE DataCacheGenerator。
SOURCE SourceGenerator。

三种生产者,SourceGenerator网络请求,DataCacheGenerator从缓存文件获取,ResourceCacheGenerator从资源文件获取。
我们再回到runGenerators方法,我们根据当前阶段,获取到对应Generator,然后执行它的startNext方法,如果失败,继续获取下一个阶段和生产者。

举个例子,我从url中load图片,这时,初始Stage是RESOURCE_CACHE,初始ResourceCacheGenerator,生产者startNext方法返回false,然后,在while循环中获取Stage是DATA_CACHE,对应生产者是DataCacheGenerator,继续startNext方法,磁盘缓存还没有存储,依然返回false。最后获取到SourceGenerator生产者,阶段变成SOURCE。这时,退出while循环,执行reschedule方法,设置该任务RunReason为SWITCH_TO_SOURCE_SERVICE,触发回调Callback的reschedule方法,EngindJob实现了该回调。再次向线程池派发该DecodeJob任务。

当再次运行DecodeJob#runWrapped方法时,RunReason已经变成了SWITCH_TO_SOURCE_SERVICE,直接执行runGenerators方法,当前生产者就是上次已经获取的SourceGenerator,执行它的startNext方法。

@Override
public boolean startNext() {
    //当已经有了网络数据时,dataToCache不空,存储磁盘缓存中。
    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 = 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;
}

当第一次来到此方法时,dataToCache是空,内部生产者DataCacheGenerator也是空。这里会调用ModelLoader.LoadData<?>内部DataFetcher的loadData方法,这里就是发起网路请求的地方。

ResourceCacheGenerator从Disk缓存中根据key获取变换过的资源,这三个Generator都会执行startNext方法,返回false,说明没有找到资源,再通过下一个Generator。
ResourceCacheGenerator中查找File是空,就不会为其创建ModelLoader列表,不会利用LoadData的DataFetcher加载数据。DataFetcher是真正的数据抓取者。

如果是资源文件,使用的是ResourceCacheGenerator生产者。当获取到的File不是空,才会生成ModelLoader列表。

再看一下DataCacheGenerator。根据originalKey获取File,当File存在时,初始化ModelLoader列表,结束循环,如果列表一直是空,会循环多次。同样,由ModelLoader来创建LoadData,利用它的DataFetcher加载数据。
ByteBufferFileLoader实现ModelLoader接口,内部ByteBufferFetcher实现DataFetcher接口,因此,调用的ByteBufferFetcher的loadData方法。结果是ByteBuffer。将该数据交给DecodeJob的onDataFetcherReady方法。
调用decodeFromFetcher方法。
该方法最后找到ByteBufferBitmapDecoder。调用它的decode方法。

当有一个startNext成功,结束掉runGenerators中的while循环。
三个Generator都实现了DataFetcher.DataCallback<Object>接口,用于加载回调,在回调方法中,统一都调用FetcherReadyCallback的回调方法。DecodeJob任务实现FetcherReadyCallback回调。

LoadPath中有一个DecodePath列表,通过调试,里面有三个DecodePath,分别是,在LoadPath的load方法中,找到每一个DecodePath,触发他们的decode方法。

资源通过EngineJob的回调方法,onResourceReady,存储在EngineJob中。然后向主线程发送一个消息,handleResultOnMainThread处理。
回调监听器EngineJobListener的方法,拿到SingleRequest,它实现了ResourceCallback,因此,回调ResourceCallback的方法,这时候已经是主线程在执行了。触发Target的onResourceReady方法,最后通知成功notifyLoadSuccess。

解析Decode是用的StreamBitmapDecoder,他在BitmapDrawableDecoder的内部,在调用BitmapDrawableDecoder的decode方法时,触发StreamBitmapDecoder的decode方法。他们都实现了ResourceDecoder接口。
StreamBitmapDecoder调用Downsampler的decode方法。传入宽高,InputStream流,获取到Bitmap,封装到BitmapResource中。

未完成,待整理


任重而道远

相关文章

网友评论

      本文标题:Glide源码分析-加载任务

      本文链接:https://www.haomeiwen.com/subject/bpsfpftx.html