Glide源碼分析執行流程

上一篇講了Glide源碼分析之Glide和RequestManager構建過程,有興趣能夠去看一下,這篇我從頭至尾又從新講解Glide從構建到請求網絡資源的整個過程,先看一下圖,這張圖是看源碼記錄的,不可能所有流程都記下來,這張圖只是把整個流程涉及到的比較重要的方法給畫出來。java

####Glide優點: 一、可配置度高,自適應度高; 二、支持多種數據源,本地、網絡、assets、gif; 三、高效緩存,支持memory和diskp圖片緩存,默認二級緩存; 四、使用BitmapPool高效處理Bitmap,避免頻繁GC; 五、圖片加載過程能夠監聽,咱們項目中使用了OkHttp做爲Glide的網絡層監聽下載圖片進度; 六、生命週期,Glide綁定Activity的生命週期;緩存

Glide網絡執行流程圖.png

從圖中看可能要分幾個模塊講,按照圖中的步驟分類講解,分爲:一、二、三、四、五、六、七、八、9,儘可能詳細,固然因爲篇幅的緣由,僅僅講解Glide請求網絡的過程,像緩存、編解碼這些基本是不會講解,不事後面會分模塊功能講解。網絡

####一、Glide的初始化app

Glide.with:ide

public static RequestManager with(FragmentActivity activity) {
    //第一步是構建RequestManagerRetriever和建立Glide,以後調用getRetriever方法
    RequestManagerRetriever requestManagerRetriever = getRetriever(activity);
    RequestManager requestManager = requestManagerRetriever.get(activity);
    return requestManager;
}


@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
}

public static Glide get(@NonNull Context context) {
    if (glide == null) {
        synchronized (Glide.class) {
            if (glide == null) {
                checkAndInitializeGlide(context);
            }
        }
    }
    return glide;
}
複製代碼

能夠看到在with方法中又調用getRetriever方法以後又調用get方法,其實真正作建立和初始化的操做在initializeGlide方法中源碼分析

private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    //Application
    Context applicationContext = context.getApplicationContext();


    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();

    //是否是在Manifest註冊了,在4.0以前就是使用了Manifest自定Module
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
        manifestModules = new ManifestParser(applicationContext).parse();
    }

    //4.0以後使用了註解的方式,可是Manifest尚未廢棄
    if (annotationGeneratedModule != null && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
        Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();
        Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
        while (iterator.hasNext()) {
            com.bumptech.glide.module.GlideModule current = iterator.next();
            if (!excludedModuleClasses.contains(current.getClass())) {
                continue;
            }
 
            }
            iterator.remove();
        }
    }
    //獲取RequestManager工程
    RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null;
    //將RequestManager工廠注入Builder
    builder.setRequestManagerFactory(factory);

    // 自定義Module,可更改Glide配置
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
        module.applyOptions(applicationContext, builder);
    }

    // 自定義Module,可更改Glide配置
    if (annotationGeneratedModule != null) {
        annotationGeneratedModule.applyOptions(applicationContext, builder);
    }

    //經過Builder建立Glide
    Glide glide = builder.build(applicationContext);

    //manifest註冊組件
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
        try {
            module.registerComponents(applicationContext, glide, glide.registry);
        } catch (AbstractMethodError e) {
        }
    }

    // 註解生成並註冊組件
    if (annotationGeneratedModule != null) {
        annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }

    // 內存監控
    applicationContext.registerComponentCallbacks(glide);
    //最後賦值
    Glide.glide = glide;
}
複製代碼

在initializeGlide方法中主要有幾點:fetch

  • 根據註解獲取各類組件和自定義模塊之類的東西動畫

    annotationGeneratedModule.applyOptions(applicationContext, builder);
    
    //經過Builder建立Glide,注意這裏爲何要把這段代碼寫在註冊組件和自定義模塊之間
      Glide glide = builder.build(applicationContext);
    
    annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    複製代碼
  • 最後將RequestManagerFactory注入GlideBiulder中:ui

    //獲取RequestManager工程
      RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null;
      //將RequestManager工廠注入Builder
      builder.setRequestManagerFactory(factory);
    複製代碼

加下來分析一下: Glide glide = builder.build(applicationContext);this

Glide build(@NonNull Context context) {
    //通常都所有判斷是否爲null,因此咱們在自定義Module時,重寫applyOptions方法,可更改配置不使用默認的配置
    if (sourceExecutor == null) {
        sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    //硬盤緩存線程池
    if (diskCacheExecutor == null) {
        diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
    // 動畫線程池
    if (animationExecutor == null) {
        animationExecutor = GlideExecutor.newAnimationExecutor();
    }
    //內存緩存大小計算
    if (memorySizeCalculator == null) {
        memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }
    //網絡監視器工程
    if (connectivityMonitorFactory == null) {
        connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
    //Bitmap複用池(享元)
    if (bitmapPool == null) {
        int size = memorySizeCalculator.getBitmapPoolSize();
        if (size > 0) {
            bitmapPool = new LruBitmapPool(size);
        } else {
            bitmapPool = new BitmapPoolAdapter();
        }
    }

    if (arrayPool == null) {
        arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
    //內存緩存
    if (memoryCache == null) {
        memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
    //磁盤緩存工廠
    if (diskCacheFactory == null) {
        diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
    if (engine == null) {
        engine = new Engine(
                memoryCache,
                diskCacheFactory,
                diskCacheExecutor,
                sourceExecutor,
                GlideExecutor.newUnlimitedSourceExecutor(),
                animationExecutor,
                isActiveResourceRetentionAllowed);
    }


    //請求觀察者,成功或失敗
    if (defaultRequestListeners == null) {
        defaultRequestListeners = Collections.emptyList();
    } else {
        defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }

    // 在Glide.java文件中 builder.setRequestManagerFactory(factory)
    // requestManagerRetriever主要是檢查RequestManager
    RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptions.lock(),
            defaultTransitionOptions,
            defaultRequestListeners,
            isLoggingRequestOriginsEnabled);
}
複製代碼

這段代碼不少,不過邏輯是通簡單的;無非就是各類線程池的構建和RequestManagerRetriever的建立還有Engine的建立這個比較重要,管理者整個Glide的資源的工做都是Engine作的。

####二、建立RequestManager和生命週期的關聯

RequestManager requestManager = requestManagerRetriever.get(activity);

在with方法中調用了requestManagerRetriever.get(activity)方法,進去瞄一眼:

public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
}
複製代碼

實際上get方法有不少重載的方法,其實邏輯是同樣的,暫時無論,先看看supportFragmentGet方法:

private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    //1 獲取Fragment
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    //嘗試在Fragment中獲取RequestManager
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {//不存在
        Glide glide = Glide.get(context);
        //建立RequestManager
        requestManager = factory.build(glide,
                current.getGlideLifecycle(),//生命週期的回調
                current.getRequestManagerTreeNode(), context);
        //並保存到Fragment中
        current.setRequestManager(requestManager);
    }
    return requestManager;
}
複製代碼

看到1了嗎:

private SupportRequestManagerFragment getSupportRequestManagerFragment(@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {

    //檢索是否存在SupportRequestManagerFragment,若是不存在則建立一個Fragmment並添加到緩存中
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {//不存在
        //嘗試從緩存中讀取
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {//仍是不存在
            //那麼就建立一個新的Fragment
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            if (isParentVisible) {
                current.getGlideLifecycle().onStart();
            }
            //添加到緩存中
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//綁定成功後則從pendingRequestManagerFragments移除fragment。這裏的pendingRequestManagerFragments主要是防止fragment重複建立,由於每一個activity必須對應一個惟一的fragment。
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}
複製代碼

檢索是否存在SupportRequestManagerFragment,若是不存在則建立一個Fragmment並添加到緩存中, 由於Glide使用一個隱藏的Fargment做爲監聽聲明週期做用,至於爲何添加Fragment又移除,我在谷歌查了一下說是這裏的pendingRequestManagerFragments主要是防止fragment重複建立,由於每一個activity必須對應一個惟一的fragment。

通過上面的步驟基本上就是Glide建立和初始化,並建立了RequestManager,並將RequestManager保存至Fragment中,以及關聯生命週期。

####三、接下來就是使用load()和into()方法:

public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
}

@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
        @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}
複製代碼

實際上load方法主要是構建RequestBuilder,接着沒什麼好說的,看一下into

private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
    Preconditions.checkNotNull(target);

    /**
     * 若是不先調用load就拋這個異常
     */
    if (!isModelSet) {
        throw new IllegalArgumentException("You must call #load() before calling #into()");
    }


    //構建請求會返回一個SingleRequest
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    Request previous = target.getRequest();

    //上一個請求的處理,就是上一個請求因爲某種緣由暫停請求
    if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
        request.recycle();
        if (!Preconditions.checkNotNull(previous).isRunning()) {
            previous.begin();
        }
        return target;
    }
    requestManager.clear(target);
    target.setRequest(request);//target綁定一個請求
    // 真正開始請求的地方
    requestManager.track(target, request);
    return target;
}
複製代碼

其實這段代碼看註釋應該就能明白大致是作什麼的,主要是若是請求暫停,就開始請求,比較重要的是requestManager.track(target, request)這段代碼是要開始新請求,Glide加載圖片的整個觸發點。

synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
}
複製代碼

走了那麼久,終於看到runRequest(),運行請求?那就看一下。

/**
 * 開始追蹤請求
 * <p>
 * Starts tracking the given request.
 */
public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
        //若是暫停就開始請求
        request.begin();
    } else {
        request.clear();
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Paused, delaying request");
        }
        //待處理的請求
        pendingRequests.add(request);
    }
}
複製代碼

仍是沒看到什麼東西, 那就看一下request.begin(),實際上應該看SingleRequest的begin方法。

@Override
public synchronized void begin() {
    if (model == null) {
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            width = overrideWidth;
            height = overrideHeight;
        }
        onLoadFailed(new GlideException("Received null model"), logLevel);
        return;
    }

    if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
    }
    //回調target,資源請求已經完成,好比內存緩存,這些不須要再請求網絡的
    if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
    }

    /**
     *
     *從新啓動既沒有完成也還沒不運行的請求,這些能夠被視爲新的請求,而且能夠從頭開始從新運行。
     */
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        //這裏面真的是要請求網絡了
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }

    /**
     * 回調給target通知請求已經開始
     *
     */
    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
    }
}
複製代碼

直接看我代碼的註釋吧,其實reSizeReady根據計算大小,而後開始加載圖片。

@Override
public synchronized void onSizeReady(int width, int height) {
    if (status != Status.WAITING_FOR_SIZE) {
        return;
    }

    // 狀態表示爲運行狀態
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    loadStatus =
            engine.load(
                    glideContext,
                    model,
                    requestOptions.getSignature(),
                    this.width,
                    this.height,
                    requestOptions.getResourceClass(),
                    transcodeClass,
                    priority,
                    requestOptions.getDiskCacheStrategy(),
                    requestOptions.getTransformations(),
                    requestOptions.isTransformationRequired(),
                    requestOptions.isScaleOnlyOrNoTransform(),
                    requestOptions.getOptions(),
                    requestOptions.isMemoryCacheable(),
                    requestOptions.getUseUnlimitedSourceGeneratorsPool(),
                    requestOptions.getUseAnimationPool(),
                    requestOptions.getOnlyRetrieveFromCache(),
                    this,
                    callbackExecutor);
    if (status != Status.RUNNING) {
        loadStatus = null;
    }
}
複製代碼

就是計算大小,而後開始加載圖片,看一下engine.load()方法吧。

public synchronized <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,
        boolean isScaleOnlyOrNoTransform,
        Options options,
        boolean isMemoryCacheable,
        boolean useUnlimitedSourceExecutorPool,
        boolean useAnimationPool,
        boolean onlyRetrieveFromCache,
        ResourceCallback cb,
        Executor callbackExecutor) {

    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;


    // -------------開始檢測緩存----------------
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options);

    // 第一級內存緩存
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        // 若是內存中有,就當即返回
        cb.onResourceReady(active, DataSource.MEMORY_CACHE);
        if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Loaded resource from active resources", startTime, key);
        }
        return null;
    }
    // 第二級內存緩存
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
        if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
        current.addCallback(cb, callbackExecutor);
        if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob = engineJobFactory.build(key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob = decodeJobFactory.build(glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb, callbackExecutor);

    // 開始執行任務
    engineJob.start(decodeJob);
    return new LoadStatus(cb, engineJob);
}
複製代碼

看代碼代碼註釋,應該差很少,主要是 engineJob.start(decodeJob)啓動線程執行任務。

public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
    ? diskCacheExecutor
    : getActiveSourceExecutor();
executor.execute(decodeJob);
複製代碼

}

既然是線程,那必然decodeJob必定是Runnable,直奔DecodeJob的run方法,看看究竟幹啥。

@Override
public void run() {
    //執行網絡
    DataFetcher<?> localFetcher = currentFetcher;
    try {
        if (isCancelled) {
            notifyFailed();
            return;
        }
        runWrapped();
    } catch (CallbackException e) {
        throw e;
    } catch (Throwable t) {
        if (stage != Stage.ENCODE) {
            throwables.add(t);
            notifyFailed();
        }
        if (!isCancelled) {
            throw t;
        }
        throw t;
    } finally {
        /**
         * 咱們自定組件時回調cleanup(),如OkHttpStreamFetcher中
         *
         */
        if (localFetcher != null) {
            localFetcher.cleanup();
        }
    }
}
複製代碼

沒看到執行什麼操做?看一下runWrapped()方法。

private void runWrapped() {
    switch (runReason) {
        case INITIALIZE://由於剛初始化,
            stage = getNextStage(Stage.INITIALIZE);
            currentGenerator = getNextGenerator();
            runGenerators();
            break;
        case SWITCH_TO_SOURCE_SERVICE:
            runGenerators();
            break;
        case DECODE_DATA:
            decodeFromRetrievedData();//直接解碼,而後返回解碼後的數據
            break;
        default:
            throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
}
複製代碼

這個方法就至關重要了,其實就是根據當前的狀態,生成加載圖片資源的代Generator,不信?那就看一下getNextGenerator方法。

private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
        case RESOURCE_CACHE:
            return new ResourceCacheGenerator(decodeHelper, this);//須要解碼被轉換以後的緩存
        case DATA_CACHE:
            return new DataCacheGenerator(decodeHelper, this);//須要解碼原圖緩存
        case SOURCE:
            return new SourceGenerator(decodeHelper, this);//原始數據代,須要加載網絡數據
        case FINISHED:
            return null;
        default:
            throw new IllegalStateException("Unrecognized stage: " + stage);
    }
}
複製代碼

無論你信不信,反正我是信了,那建立這些加載圖片資源幹啥?回到剛纔的runWrapper方法,盡然還有runGenerators方法,看一波。

private void runGenerators() {
    boolean isStarted = false;

    /**
     *
     * 若是getNextGenerator()返回SourceGenerator類,那麼須要請求網絡了
     * 開始網絡請求圖片
     */
    while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
        stage = getNextStage(stage);
        currentGenerator = getNextGenerator();

        if (stage == Stage.SOURCE) {
            //從新調度startNext()
            reschedule();
            return;
        }
    }
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
        notifyFailed();
    }
}
複製代碼

代碼很少,看一下currentGenerator.startNext(),這個方法是啓動圖片加載代Generator的,是個接口,那咱們選SourceGenerator這個吧。

/**
 * 準備開始拉取網絡數據
 *
 * @return
 */
@Override
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 = helper.getLoadData().get(loadDataListIndex++);

        if (loadData != null &&
                (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
                        || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
            started = true;

            /**
             *  DataFetcher的loadData()方法的回調時機,請看實現類{@link HttpUrlFetcher}
             *
             *  還把回調傳進去
             */
            loadData.fetcher.loadData(helper.getPriority(), this);
        }
    }
    return started;
}
複製代碼

DataFetcherGenerator有三個子類分別作不一樣的事情,

  • SourceGenerator: 使用已註冊的ModelLoaders和爲加載提供的model,從原始源數據生成DataFetcher DataFetchers。 根據磁盤緩存策略,源數據可能首先寫入磁盤,而後從緩存文件加載而不是直接返回。

  • ResourceCacheGenerator 從已轉換的資源數據的緩存文件中採樣數據生成DataFetchers。

  • DataCacheGenerator 從原始未修改源數據的緩存文件採樣數據生成DataFetchers。

選SourceGenetator分析:

loadData.fetcher.loadData(helper.getPriority(), this);
複製代碼

使用已註冊的ModelLoaders和load提供的model,從原始源數據生成DataFetchers。 根據磁盤緩存策略,源數據可能首先寫入磁盤,而後從緩存文件加載而不是直接返回。

private volatile ModelLoader.LoadData<?> loadData;


class LoadData<Data> {
    public final Key sourceKey;
    public final List<Key> alternateKeys;
    public final DataFetcher<Data> fetcher;

        public LoadData(@NonNull Key sourceKey, @NonNull DataFetcher<Data> fetcher) {
        this(sourceKey, Collections.<Key>emptyList(), fetcher);
    }

    public LoadData(@NonNull Key sourceKey, @NonNull List<Key> alternateKeys,
                    @NonNull DataFetcher<Data> fetcher) {
        this.sourceKey = Preconditions.checkNotNull(sourceKey);
        this.alternateKeys = Preconditions.checkNotNull(alternateKeys);
        this.fetcher = Preconditions.checkNotNull(fetcher);
    }
}
複製代碼

其實是若是咱們自定義模塊,那麼會從DataFetcher和ModelLoader中去作網絡請求。自此文章結束。

相關文章
相關標籤/搜索