Glide源码浅析

前言

之前对Glide的认知一直停留在一行代码就能够完成图片加载,如今就来尝试探索下这一行代码下,Glide到底作了些什么。本文基于Glide4.8.0java

1、基本使用

以加载一张普通的网络图片为例缓存

val jpg = "http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg"
Glide.with(this)
     .load(img)
     .into(iv)
复制代码

就这么核心的一行代码一张图片就会加载到iv中去了,下面从with开始分析下它的源码bash

2、with()

with方法提供了不少方法重载,入参都是一些能直接或间接取到Context实例的类型,其基本流程以下网络

下面根据这个流程来看看源码app

// Glide.java
public static RequestManager with(@NonNull FragmentActivity activity) {
	return getRetriever(activity).get(activity);
}
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;
}
private static void checkAndInitializeGlide(@NonNull Context context) {
    initializeGlide(context);
}
private static void initializeGlide(@NonNull Context context) {
    initializeGlide(context, new GlideBuilder());
}
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    RequestManagerRetriever.RequestManagerFactory factory = null;
    builder.setRequestManagerFactory(factory);
    Glide glide = builder.build(applicationContext);
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
}
复制代码

经过源码发现getRetriever方法内部其实就是建立了Glide实例,而且调用其getRequestManagerRetriever,先来看看Glide实例的构建过程ide

Glide build(@NonNull Context context) {
    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();
    }
    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(),
                        GlideExecutor.newAnimationExecutor(),
                        isActiveResourceRetentionAllowed);
    }
    RequestManagerRetriever requestManagerRetriever =
            new RequestManagerRetriever(requestManagerFactory);
    return new Glide(...);
}
复制代码

能够看到内部先是构建了三个线程池,而后新建了一个Engine类实例,建立了RequestManagerRetriever实例,该实例就是调用getRequestManagerRetriever获取到的实例。接着看看Glide的构造方法。oop

Glide(...) {
    registry = new Registry();
    // 这里注册了不少东西,好比编码器、解码器、工厂类、转换器。这里只是挑了几个
    registry
        // 注册Encoder 
        .append(ByteBuffer.class, new ByteBufferEncoder())
        // 注册Decoder
        .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
        // 注册ModelLoaderFactory,三个参数分别是Model类型,Data类型,ModelLoader工厂
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        // 注册Transcoders
        .register(Bitmap.class,BitmapDrawable.class,new BitmapDrawableTranscoder(resources))
    ...
    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    glideContext = new GlideContext(...);
}
复制代码
  • 注册Encoder最终会保存在registry的encoderRegistry变量中
  • 注册Decoder最终会保存在registry的decoderRegistry变量中
  • 注册ModelLoaderFactory最终会保存到registry的modelLoaderRegistry变量中的multiModelLoaderFactory变量中
  • 注册Transcoders最终会保存到transcoderRegistry中

获取到了RequestManagerRetriever实例后继续调用其get方法fetch

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));
    }
}
复制代码

这里先分析主线程调用的状况,所以接着调用supportFragmentGetui

private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        Glide glide = Glide.get(context);
        requestManager =
            factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
        current.setRequestManager(requestManager);
    }
    return requestManager;
}
private SupportRequestManagerFragment getSupportRequestManagerFragment( @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    // 首先看看当前页面是否已经有指定Fragment了,若是没有那么就新建一个而且加入到当前页面中去
    SupportRequestManagerFragment current =
            (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            if (isParentVisible) {
                current.getGlideLifecycle().onStart();
            }
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}
复制代码

能够看到supportFragmentGet首先将一个Fragment添加到当前页面(用于观察Activity的生命周期),而后建立一个RequestManager实例并返回,with方法结束而后看看load方法this

3、load()

load方法位于RequestManager中用于将指定资源做为数据源这里以参数为String为例

下面根据这个流程来看看源码

// RequestManager.java
public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}
复制代码

asDrawable内部只是建立了一个RequestBuilder实例,接着再调用其load方法

// RequestBuilder.java
public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
}
复制代码

load方法内部也就是进行了简单赋值就将本身返回了,至此load方法也已经结束了,接着看看重点into方法

4、into()

into方法一样定义在RequestBuilder中,主要用于将加载到的图片传递给指定Target实例,这个方法内部至关复杂,也是本文的重点。

// RequestBuilder.java
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                requestOptions = requestOptions.clone().optionalCenterCrop();
                break;
            case CENTER_INSIDE:
                requestOptions = requestOptions.clone().optionalCenterInside();
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                requestOptions = requestOptions.clone().optionalFitCenter();
                break;
            case FIT_XY:
                requestOptions = requestOptions.clone().optionalCenterInside();
                break;
            case CENTER:
            case MATRIX:
            default:
        }
    }
    return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions);
}
复制代码

这里会对RequestOptions作一些转化,而后调用buildImageViewTarget构造指定的target。

// GlideContext.java
public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
// ImageViewTargetFactory.java
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
        return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
        return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
        throw new IllegalArgumentException(
            "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
}
复制代码

因为刚才调用了asDrawable因此会新建一个DrawableImageViewTarget实例返回,接着继续看看into方法

private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull RequestOptions options) {
    if (!isModelSet) {
        throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
}
复制代码

into方法内部首先判断了是否调用了load方法而后调用buildRequest建立Request实例,而后调用track方法执行Request

private Request buildRequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, RequestOptions requestOptions) {
    return buildRequestRecursive(...);
}
private Request buildRequestRecursive(...) {
    Request mainRequest =
            buildThumbnailRequestRecursive(...);
    if (errorRequestCoordinator == null) {
        return mainRequest;
    }
    Request errorRequest = errorBuilder.buildRequestRecursive(...);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
}
private Request buildThumbnailRequestRecursive(...) {
    // 只考虑没有缩略图的状况了
    return obtainRequest(...);
}
private Request obtainRequest(...) {
    return SingleRequest.obtain(...);
}
复制代码

能够看到当没有缩略图的时候会经过调用SingleRequest.obtain新建一个SingleRequest实例,接着看看requestManager.track是怎么执行Request的

// RequestManager.java
void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
        request.begin();
    } else {
        request.clear();
        pendingRequests.add(request);
    }
}
复制代码

若是没有被暂定的话就接着继续执行SingleRequest的begin方法

// SingleRequest.java
public void begin() {
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }
}
复制代码

根据是否设置了宽高来决定是调用onSizeReady仍是target.getSize,先假设没有设置宽高来看看DrawableImageViewTarget实例的getSize方法

// getSize继承自ViewTarget
public void getSize(@NonNull SizeReadyCallback cb) {
    sizeDeterminer.getSize(cb);
}
// SizeDeterminer.java
void getSize(@NonNull SizeReadyCallback cb) {
    int currentWidth = getTargetWidth();
    int currentHeight = getTargetHeight();
    if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
        return;
    }
    if (!cbs.contains(cb)) {
        cbs.add(cb);
    }
    if (layoutListener == null) {
        ViewTreeObserver observer = view.getViewTreeObserver();
        layoutListener = new SizeDeterminerLayoutListener(this);
        observer.addOnPreDrawListener(layoutListener);
    }
}
private int getTargetWidth() {
    int horizontalPadding = view.getPaddingLeft() + view.getPaddingRight();
    LayoutParams layoutParams = view.getLayoutParams();
    int layoutParamSize = layoutParams != null ? layoutParams.width : PENDING_SIZE;
    return getTargetDimen(view.getWidth(), layoutParamSize, horizontalPadding);
}
private int getTargetHeight() {
    int verticalPadding = view.getPaddingTop() + view.getPaddingBottom();
    LayoutParams layoutParams = view.getLayoutParams();
    int layoutParamSize = layoutParams != null ? layoutParams.height : PENDING_SIZE;
    return getTargetDimen(view.getHeight(), layoutParamSize, verticalPadding);
}
private int getTargetDimen(int viewSize, int paramSize, int paddingSize) {
    int adjustedParamSize = paramSize - paddingSize;
    if (adjustedParamSize > 0) {
        return adjustedParamSize;
    }
    if (waitForLayout && view.isLayoutRequested()) {
        return PENDING_SIZE;
    }
    int adjustedViewSize = viewSize - paddingSize;
    if (adjustedViewSize > 0) {
        return adjustedViewSize;
    }
    if (!view.isLayoutRequested() && paramSize == LayoutParams.WRAP_CONTENT) {
        return getMaxDisplayLength(view.getContext());
    }
    return PENDING_SIZE;
}
复制代码

getSize内部经过获取View的长宽减去对应的padding作为目标宽高,而后又回调了onSizeReady方法,注意若是在此时目标ImageView尚未进行三大流程(也就是说获取不到宽高)那么会注册回调,在回调中会调用onSizeReady方法这里就不展开了,所以不论是否指定了宽高最终都会调用SingleRequest的onSizeReady方法

// SingleRequest.java
public void onSizeReady(int width, int height) {
    status = Status.RUNNING;
    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
    loadStatus = engine.load(...);
}
复制代码

onSizeReady内部就分为三步首先改变状态为Running而后计算最终须要加载的宽高,最后调用engine.load加载资源

public <R> LoadStatus load(...) {
    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);
        if (VERBOSE_IS_LOGGABLE) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }
    EngineJob<R> engineJob =
            engineJobFactory.build(...);
    DecodeJob<R> decodeJob =
            decodeJobFactory.build(...);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(decodeJob);
    return new LoadStatus(cb, engineJob);
}
复制代码

load方法首先构建一个EngineKey实例,内部只是重写了hashCode和equal方法,接着若是容许读取内存缓存就尝试从ActivityResources中读取读不到再从MemoryCache中读取,Tip: 暂时没分清这二者的区别。若是已经有了当前key对应的EngineJob就直接返回,接着建立一个EngineJob和一个DecodeJob实例,而后调用engineJob.start

// EngineJob.java
public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
}
// DecodeJob.java
boolean willDecodeFromCache() {
    Stage firstStage = getNextStage(Stage.INITIALIZE);
    return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
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:
            throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
}
复制代码

首先根据是否从缓存中解码选取线程池,接着使用线程池执行DecodeJob,而若是没有设置DiskCacheStrategy那么默认的DiskCacheStarategy.Automatic的decodeCachedResource返回true,因此willDecodeFromCache会返回true,因此最终executor会是diskCacheExecutor,而这个线程池就是在构建Glide实例的时候建立的diskCacheExecutor,接着看看DecodeJob的run方法

// DecodeJob.java
public void run() {
    DataFetcher<?> localFetcher = currentFetcher;
    try {
        if (isCancelled) {
            notifyFailed();
            return;
        }
        runWrapped();
    } catch (Throwable t) {
        ...
    }
}
复制代码

若是取消了,就通知下失败,不然主要就是调用了runWrapped

// DecodeJob.java
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);
    }
}
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);
    }
}
复制代码

因为DecodeJob实例刚刚建立因此runReason为构造器时初始化的RunReason.INITIALIZE状态,getNextStage返回Stage.RESOURCE_CACHE,getNextGenerator返回一个ResourceCacheGenerator实例,接着看看runGenerator方法

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();
    }
}
复制代码

内部调用了startNext方法,并根据其返回值判断是否进入下一步,先来看看ResourceCacheGenerator的startNext方法

// ResourceCacheGenerator.java
public boolean startNext() {
    List<Key> sourceIds = helper.getCacheKeys();
    if (sourceIds.isEmpty()) {
        return false;
    }
    List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
    if (resourceClasses.isEmpty()) {
        if (File.class.equals(helper.getTranscodeClass())) {
            return false;
        }
    }
    while (modelLoaders == null || !hasNextModelLoader()) {
        resourceClassIndex++;
        if (resourceClassIndex >= resourceClasses.size()) {
            sourceIdIndex++;
            if (sourceIdIndex >= sourceIds.size()) {
                return false;
            }
            resourceClassIndex = 0;
        }
        // 获取GlideUrl
        Key sourceId = sourceIds.get(sourceIdIndex);
        Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
        Transformation<?> transformation = helper.getTransformation(resourceClass);
        currentKey =
                new ResourceCacheKey(...);
        cacheFile = helper.getDiskCache().get(currentKey);
        if (cacheFile != null) {
            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;
            loadData.fetcher.loadData(helper.getPriority(), this);
        }
    }
    return started;
}
复制代码

getCacheKey这个方法内部很是复杂,一步步来进行分析

// DecoderHelp.java
List<Key> getCacheKeys() {
    if (!isCacheKeysSet) {
        isCacheKeysSet = true;
        cacheKeys.clear();
        List<LoadData<?>> loadData = getLoadData();
        for (int i = 0, size = loadData.size(); i < size; i++) {
            LoadData<?> data = loadData.get(i);
            if (!cacheKeys.contains(data.sourceKey)) {
                cacheKeys.add(data.sourceKey);
            }
            for (int j = 0; j < data.alternateKeys.size(); j++) {
                if (!cacheKeys.contains(data.alternateKeys.get(j))) {
                    cacheKeys.add(data.alternateKeys.get(j));
                }
            }
        }
    }
    return cacheKeys;
}
List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
        isLoadDataSet = true;
        loadData.clear();
        List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
        for (int i = 0, size = modelLoaders.size(); i < size; i++) {
            ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
            LoadData<?> current =
                    modelLoader.buildLoadData(model, width, height, options);
            if (current != null) {
                loadData.add(current);
            }
        }
    }
    return loadData;
}
// Registry.java
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
    List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
    if (result.isEmpty()) {
        throw new NoModelLoaderAvailableException(model);
    }
    return result;
}

public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
    for (int i = 0; i < size; i++) {
        ModelLoader<A, ?> loader = modelLoaders.get(i);
        if (loader.handles(model)) {
            if (isEmpty) {
                filteredLoaders = new ArrayList<>(size - i);
                isEmpty = false;
            }
            filteredLoaders.add(loader);
        }
    }
    return filteredLoaders;
}
private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
            @NonNull Class<A> modelClass) {
    List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
    if (loaders == null) {
        loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
        cache.put(modelClass, loaders);
    }
    return loaders;
}
// MultiModelLoaderFactory.java
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
    try {
        List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
        for (Entry<?, ?> entry : entries) {
            if (alreadyUsedEntries.contains(entry)) {
                continue;
            }
            if (entry.handles(modelClass)) {
                alreadyUsedEntries.add(entry);
                // 这个地方可能会触发递归,为了防止栈溢出,用过的entry不容许再用
                loaders.add(this.<Model, Object>build(entry));
                alreadyUsedEntries.remove(entry);
            }
        }
        return loaders;
    } catch (Throwable t) {
        alreadyUsedEntries.clear();
        throw t;
    }
}
private <Model, Data> ModelLoader<Model, Data> build(@NonNull Entry<?, ?> entry) {
    return (ModelLoader<Model, Data>) Preconditions.checkNotNull(entry.factory.build(this));
}
复制代码

1.1 Model(String) ——> Date(Any)

getCacheKeys内部的一个getLoadData的代码就很长,通过层层调用最终会调用到build方法从Glide实例一建立就注册的的全部Factory中找寻到全部能处理Model类型为String的Factory,也就是以下四个

.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
复制代码

2.1 Model(String) ——> Data(InputStream): DataUrlLoader

这四个来一个个进行分析(为何要一个个分析接着看就知道了),首先会调用到DataUrlLoader.StreamFactory的build方法

// DataUrlLoader.StreamFactory.java
public ModelLoader<Model, InputStream> build( @NonNull MultiModelLoaderFactory multiFactory) {
  return new DataUrlLoader<>(opener);
}
复制代码

内部简单的建立了一个DataUrlLoader实例,而后将其放入到了loaders中。

2.2 Model(String) ——> Model(Uri) ----> Data(InputStream)

接着看看第二个StringLoader.StreamFactory的build方法

// StringLoader.StreamFactory.java
public ModelLoader<String, InputStream> build( @NonNull MultiModelLoaderFactory multiFactory) {
  return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
}
复制代码

此次跟DataUrlLoader.StreamFactory不同了,内部建立了一个StringLoader实例,可是又回调了MultiModelLoaderFactory两个参数的build方法,而且明确指定了要寻找能将Model类型为Uri的处理成Data类型为InputStream的Factory,先来看看两个参数的build方法

// MultiModelLoaderFactory.java
public synchronized <Model, Data> ModelLoader<Model, Data> build(Class<Model> modelClass, Class<DatdataClass) {
    try {
        List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
        boolean ignoredAnyEntries = false;
        for (Entry<?, ?> entry : entries) {
            if (alreadyUsedEntries.contains(entry)) {
                ignoredAnyEntries = true;
                continue;
            }
            if (entry.handles(modelClass, dataClass)) {
                alreadyUsedEntries.add(entry);
                loaders.add(this.<Model, Data>build(entry));
                alreadyUsedEntries.remove(entry);
            }
        }
        if (loaders.size() > 1) {
            return factory.build(loaders, throwableListPool);
        } else if (loaders.size() == 1) {
            return loaders.get(0);
        } else {
            if (ignoredAnyEntries) {
                return emptyModelLoader();
            } else {
                throw new NoModelLoaderAvailableException(modelClass, dataClass);
            }
        }
    } catch (Throwable t) {
        alreadyUsedEntries.clear();
        throw t;
    }
}
复制代码

代码基本与一个参数的build方法相似,不一样点在于明确指定了目标Data类型和返回类型,那么以前在注册列表中寻找Model类型为Uri,Data类型为InputStream的factory,以下所示

.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
.append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
.append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context))
.append(Uri.class, InputStream.class, new UriLoader.StreamFactory(contentResolver))
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
复制代码

有7个Factory知足条件,那么依次再来看这7个Factory的build方法

2.2.1 Model(String) ——> Model(Uri) ——> Data(InputStream): DataUrlLoader

// DataUrlLoader.StreamFactory.java
public ModelLoader<Model, InputStream> build( @NonNull MultiModelLoaderFactory multiFactory) {
  return new DataUrlLoader<>(opener);
}
复制代码

这个没什么特别的接着看下一个

2.2.2 Model(String) ——> Model(Uri): HttpUriLoader ---> Model(GlideUrl) ——> Data(InputStream)

// HttpUriLoader.Factory.java
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
}
复制代码
2.2.2.1 Model(String) ——> Model(Uri) ——> Model(GlideUrl) ——> Data(InputStream)

构建HttpUrlLoader的时候又要去寻找能将Model类型为GlideUrl处理成Data类型为InputStream的Factory,那么接着看,经过查询注册,只发现了如下一个。

.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
复制代码

那么直接看看其build方法

// HttpGlideUrlLoader.Factory.java
public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new HttpGlideUrlLoader(modelCache);
}
复制代码

只是建立了一个HttpGlideUrlLoader实例就返回(这个实例才是真正的去请求网络数据),接着看其他5个能将Model(Uri)处理成Data(InputStream)的Factory

2.2.3 Model(String) ——> Model(Uri) ——> Data(InputStream): StreamAssetPathFetcher

// AssetUriLoader.StreamFactory.java
public DataFetcher<InputStream> buildFetcher(AssetManager assetManager, String assetPath) {
    return new StreamAssetPathFetcher(assetManager, assetPath);
}
复制代码

方法内部仅仅建立了一个StreamAssetPathFetcher实例接着看看下一个

2.2.4 Model(String) ——> Model(Uri) ——> Data(InputStream): MediaStoreImageThumbLoader

// MediaStoreImageThumbLoader.Factory
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new MediaStoreImageThumbLoader(context);
}
复制代码

方法内部仅仅建立了一个MediaStoreImageThumbLoader实例接着看看下一个

2.2.5 Model(String) ——> Model(Uri) ——> Data(InputStream): MediaStoreVideoThumbLoader

// MediaStoreVideoThumbLoader.java
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new MediaStoreVideoThumbLoader(context);
}
复制代码

方法内部仅仅建立了一个MediaStoreVideoThumbLoader实例接着看看下一个

2.2.6 Model(String) ——> Model(Uri) ——> Data(InputStream): UriLoader

public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new UriLoader<>(this);
}
复制代码

方法内部仅仅建立了一个UriLoader实例接着看看最后一个

2.2.7 Model(String) ——> Model(Uri): UrlUriLoader ---> Model(GlideUrl) ——> Data(InputStream)

public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
    return new UrlUriLoader<>(multiFactory.build(GlideUrl.class, InputStream.class));
}
复制代码

内部又寻找能将GlideUrl处理成InputStream的Factory,通过上面的分析也就只有HttpGlideUrlLoader.Factory能进行处理这里进再也不展开。

2.3 Model(String) ——> Model(Uri) ---> Data(ParcelFileDescriptor)

接着看能将Model(String)处理成Data(Any)的第三个Factory(StringLoader.FileDescriptorFactory)

// StringLoader.FileDescriptorFactory
public ModelLoader<String, ParcelFileDescriptor> build( @NonNull MultiModelLoaderFactory multiFactory) {
    return new StringLoader<>(multiFactory.build(Uri.class, ParcelFileDescriptor.class));
}
复制代码

内部再去寻找能将Uri处理成ParcelFileDescriptor的Factory,经过查询有如下两个

.append(Uri.class,ParcelFileDescriptor.class, new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
.append(Uri.class, ParcelFileDescriptor.class, new UriLoader.FileDescriptorFactory(contentResolver))
复制代码

再来分别看看

2.3.1 Model(String) ——> Model(Uri) ——> Data(ParcelFileDescriptor): AssetUriLoader

// AssetUriLoader.FileDescriptorFactory.java
public ModelLoader<Uri, ParcelFileDescriptor> build(MultiModelLoaderFactory multiFactory) {
    return new AssetUriLoader<>(assetManager, this);
}
复制代码

内部仅仅建立了AssetUriLoader,接着看下一个

2.3.2 Model(String) ——> Model(Uri) ——> Data(ParcelFileDescriptor): UriLoader

// UriLoader.FileDescriptorFactory.java
public ModelLoader<Uri, ParcelFileDescriptor> build(MultiModelLoaderFactory multiFactory) {
    return new UriLoader<>(this);
}
复制代码

2.4 Model(String) ——> Model(Uri) ---> Data(AssetFileDescriptor)

接着看能将Model(String)处理成Data(Any)的最后一个Factory(StringLoader.AssetFileDescriptorFactory)

// StringLoader.AssetFileDescriptorFactory.java
public ModelLoader<String, AssetFileDescriptor> build( @NonNull MultiModelLoaderFactory multiFactory) {
    return new StringLoader<>(multiFactory.build(Uri.class, AssetFileDescriptor.class));
}
复制代码

内部又去寻找能将Uri处理成AssetFileDescriptor的Factory,经过查询就找到了下面这一个

.append(Uri.class, AssetFileDescriptor.class, new UriLoader.AssetFileDescriptorFactory(contentResolver))
复制代码

2.4.1 Model(String) ——> Model(Uri) ——> Data(AssetFileDescriptor): UriLoader

// UriLoad.AssetFileDescriptorFactory.java
public ModelLoader<Uri, AssetFileDescriptor> build(MultiModelLoaderFactory multiFactory) {
    return new UriLoader<>(this);
}
复制代码

而后调用入参为Entry的build方法,内部调用了entry.factory.build(this),也就是分别调用上述4个Factory的build方法。到如今为止也就刚刚分析好了MultiModelLoaderFactory.build(String.class)这么一个方法调用,先来总结下。

3 总结

能够看到Glide会寻找全部能处理Model类型String的Factory调用其build方建立ModelLoader,可是有些ModelLoader单独也不能完成一个转换,所以这些ModelLoader一般会有另外一个能帮助其完成转换的ModelLoader实例,来举个例子,StringLoader没办法将Model(String)处理成Data(InputSteam),所以其持有了一个能将Model(Uri)处理能Data(InputStream)的ModelLoad,StringLoader主要功能就是在外界调用buildLoadData时将String类型的Url转换为Uri而后调用那个持有的ModelLoader的buildLoadData方法,最终可能的转化路线以下所示

  • Model(String) ——> Data(InputStream)
  • Model(String) ——> Model(Uri) ——> Data(InputStream)
  • Model(String) ——> Model(Uri) ——> Model(GlideUrl) ——> Data(InputStream)
  • Model(String) ——> Model(Uri) ——> Data(ParcelFileDescriptor)
  • Model(String) ——> Model(Uri) ——> Data(AssetFileDescriptor)

接着再回到getModelLoaders里面执行剩余代码

public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
    for (int i = 0; i < size; i++) {
        ModelLoader<A, ?> loader = modelLoaders.get(i);
        if (loader.handles(model)) {
            if (isEmpty) {
                filteredLoaders = new ArrayList<>(size - i);
                isEmpty = false;
            }
            filteredLoaders.add(loader);
        }
    }
    return filteredLoaders;
}
// DataUrlLoader.java
public boolean handles(@NonNull Model model) {
    return model.toString().startsWith(DATA_SCHEME_IMAGE);
}
复制代码

MultiModelLoaderFactory.build只是从全部Factory中找寻出全部能处理Model(String)的Factory,可是有些ModelLoader虽然说也能处理Model(String),可是拥有其局限性好比DataUrlLoader.StreamFactory.build产生的DataUrlLoader其只能处理以data:image开头的字符串,所以当该方法返回时还余下3个ModelLoader,接着再回到DecodeHelp.getLoadData中

// DecodeHelper.java
List<LoadData<?>> getLoadData() {
    ...
    List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
    for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
            loadData.add(current);
        }
    }
    return loadData;
}
复制代码

三个StringLoader.buildLoadData

内部分别调用了三个StringLoader的buildLoadData来构建LoadData实例

public LoadData<Data> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
}
复制代码

能够看到首先将传入的String类型的url转化为Uri实例,而后调用uriLoader.buildLoadData构建LoadData,一个典型的代理模式,通过前面的分析uriLoader实际上是一个MutiModelLoader(内部有7个ModelLoader,这7个都能将Model(Uri)处理成Data(InputStream))

// MultiModelLoader.java
public LoadData<Data> buildLoadData(@NonNull Model model, int width, int height, @NonNull Options options) {
    Key sourceKey = null;
    int size = modelLoaders.size();
    List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
    for (int i = 0; i < size; i++) {
        ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
        if (modelLoader.handles(model)) {
            LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
            if (loadData != null) {
                sourceKey = loadData.sourceKey;
                fetchers.add(loadData.fetcher);
            }
        }
    }
    return !fetchers.isEmpty() && sourceKey != null
            ? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool)) : null;
}
复制代码

首先第一个DataUrlLoader因为只能处理data:image开头的字符串,因此留下6个,来看看第二个HttpUriLoader

public LoadData<InputStream> buildLoadData(@NonNull Uri model, int width, int height, @NonNull Options options) {
    return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
}
复制代码

哎,又跑去调用urlLoader.buildLoadData一层层真深,这个urlLoader仍是包含了HttpGlideUrlLoader对应于前面讲的2.2.2.1

// HttpGlideUrlLoader.java
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    GlideUrl url = model;
    if (modelCache != null) {
        url = modelCache.get(model, 0, 0);
        if (url == null) {
            modelCache.put(model, 0, 0, model);
            url = model;
        }
    }
    int timeout = options.get(TIMEOUT);
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
复制代码

千辛万苦找到了返回的第一个LoadData,注意内部传入了一个HttpUrlFetcher,后面会用于网络请求,继续第三个AssetUriLoader

// AssetUriLoader.java
public boolean handles(@NonNull Uri model) {
    return ContentResolver.SCHEME_FILE.equals(model.getScheme()) && !model.getPathSegments()
        .isEmpty() && ASSET_PATH_SEGMENT.equals(model.getPathSegments().get(0));
}
复制代码

很明显model的scheme是http因此AssetUriLoader不知足,相似的后面三个MediaStoreImageThumbLoader、MediaStoreVideoThumbLoader、UriLoader也无法处理,直接看最后一个UrlUriLoader

// UrlUriLoader.java
private static final Set<String> SCHEMES = Collections.unmodifiableSet(
    new HashSet<>(
        Arrays.asList(
          "http",
          "https"
        )
    )
);
public boolean handles(@NonNull Uri uri) {
    return SCHEMES.contains(uri.getScheme());
}
复制代码

很明显能够处理,继续看其buildLoadData方法

public LoadData<Data> buildLoadData(@NonNull Uri uri, int width, int height, @NonNull Options options) {
    GlideUrl glideUrl = new GlideUrl(uri.toString());
    return urlLoader.buildLoadData(glideUrl, width, height, options);
}
复制代码

构建了一个GlideUrl实例,这里的urlLoader是一个HttpGlideUrlLoader实例对应于2.2.7,这个结果与第二个HttpUriLoader处理结果一致,第一个StringLoader到此结束,一共返回两个DataFetcher,都是HttpUrlFetcher,封装成一个LoadData(MultiFetcher)返回,后面的第2、第三个ModelLoader都不符合条件,因此最后getLoadData只会返回一个LoadData,那么getCacheKeys也就只会返回拥有一个Key的列表,继续回到ResourceCacheGenerator.startNext,方法后面根据全部注册的decoder、modelLoader、transCodeClass查询到全部能够将Data转化为对应Resource的类,最后因为没有缓存startNext最终会返回false,DataCacheGenerator也是一样的道理,最后走到SourceGenerator中

// SourceGenerator.java
public boolean startNext() {
    ...
    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;
}
复制代码

注意这里helper.getLoadData()获取到的就是刚开始ResourceCacheGenerator调用getLoadData保存在其中的一个列表,接着会调用fetcher.loadData,前面已经分析过fetcher就是MultiFetcher,内部拥有两个HttpUrlFetcher

// MultiFetcher.java
public void loadData( @NonNull Priority priority, @NonNull DataCallback<? super Data> callback) {
    this.priority = priority;
    this.callback = callback;
    exceptions = throwableListPool.acquire();
    fetchers.get(currentIndex).loadData(priority, this);
}
复制代码

这里只会启动第一个HttpUrlFetcher,第二个只会在第一个失败的时候才会调用,继续看看HttpUrlFetcher.loadData

public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
        InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
        callback.onDataReady(result);
    } catch (IOException e) {
        callback.onLoadFailed(e);
    }
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
    ...
    urlConnection = connectionFactory.build(url);
    ...
    urlConnection.setInstanceFollowRedirects(false);
    urlConnection.connect();
    stream = urlConnection.getInputStream();
    if (isCancelled) {
        return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (isHttpOk(statusCode)) {
        return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
        ...
        return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    }
    ...
}
复制代码

内部也就是直接使用了HttpUrlConnection,而且支持重定向(最多5次),若是请求成功了则会返回一个InputStream实例,而且回调callback.onDataReady,这里的callback就是MultiFetcher

// MultiFetcher.java
public void onDataReady(@Nullable Data data) {
    if (data != null) {
        callback.onDataReady(data);
    } else {
        startNextOrFail();
    }
}
复制代码

若是加载成功了那么再回调onDataReady,否则就使用下一个Fetcher请求数据或者只会返回错误,这里只看正返回成功的状况,callback是SourceGenerator

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);
    }
}
复制代码

默认的DiskCacheStrategy是AUTOMATIC,因此传入的REMOTE知足第一个If条件,cb是DecodeJob实例

// DecodeJob.java
public void reschedule() {
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
    callback.reschedule(this);
}
public void reschedule(DecodeJob<?> job) {
    getActiveSourceExecutor().execute(job);
}
复制代码

接着又会执行这个DecodeJob,不过此次与第一次不一样,此次调用是DecodeJob不是新建的其成员都维持着 执行顺序 DecodeJob.run -> runWrapped -> runGenerators -> SourceGenerator.startNext

// SourceGenerator.java
public boolean startNext() {
    if (dataToCache != null) {
        Object data = dataToCache;
        dataToCache = null;
        cacheData(data);
    }
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
        return true;
    }
}
复制代码

此次dataToCache不是null了而是一个InputStream实例

private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
        Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
        DataCacheWriter<Object> writer =
                new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
        originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
        helper.getDiskCache().put(originalKey, writer);
        ...
    } finally {
        loadData.fetcher.cleanup();
    }
    sourceCacheGenerator =
            new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
复制代码

首先获取到能处理InoutStream的Encoder也就是StreamEncoder,接着内部会调用到DiskLruCacheWrapper.put,方法内部又会执行Encoder.encode将输入流写入到文件中,这就不展开了。而且最后将sourceCacheGenerator进行了赋值(注意在建立DataCacheGenerator时传入的callback是SourceGenerator自己),因此会执行DataCacheGenerator.startNext

// DataCacheGenerator.java
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;
            loadData.fetcher.loadData(helper.getPriority(), this);
        }
    }
    return started;
}
复制代码

内部根据缓存Key获取到刚刚保存的缓存文件,而后获取全部能处理Model(File)类型的ModelLoader,接着将其遍历构建LoadData,这里就不看getModelLoaders内部实现逻辑,直接用ByteBufferFileLoader进行分析,经过调用buildLoadData会构建出一个ByteBufferFetcher实例,接着看看其loadData方法

// ByteBufferFetcher.java
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);
}
复制代码

将文件中全部的内容所有读取到ByteBuffer中后回调onDataReady方法内部通过一层层调用最终调用了DecodeJob.decodeFromRetrievedData,到如今为止数据还所有在这个byteBuffer中去,接下来就是寻找对应的decoder将其加载成一个Bitmap而后设置给ImageView,通过一系列判断,最终会寻找到ByteBufferBitmapDecoder

public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width, int height, @NonNull Options options) throws IOException {
    InputStream is = ByteBufferUtil.toStream(source);
    return downsampler.decode(is, width, height, options);
}
复制代码

downSampler里面作了真正的操做,好比缩放图片适应当前的ImageView大小等,接着判断是否要将转化后的图片进行缓存,最后就通知外界图片加载成功。

// DecodeJob.java
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
}
// EngineJob.java
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private static final Handler MAIN_THREAD_HANDLER =
      new Handler(Looper.getMainLooper(), new MainThreadCallback());
复制代码

那么最后接受消息的就是MainThreadCallback

public boolean handleMessage(Message message) {
    EngineJob<?> job = (EngineJob<?>) message.obj;
    switch (message.what) {
        case MSG_COMPLETE:
            job.handleResultOnMainThread();
            break;
        ...
        default:
            throw new IllegalStateException("Unrecognized message: " + message.what);
    }
    return true;
}
复制代码

这里最终通过一层层回调会在主线程调用ImageViewTarget.onResourceReady

// ImageViewTarget.java
 public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
        setResourceInternal(resource);
    } else {
        maybeUpdateAnimatable(resource);
    }
}
private void setResourceInternal(@Nullable Z resource) {
    setResource(resource);
    maybeUpdateAnimatable(resource);
}
protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
}
复制代码

到此为止一张图片就加载完毕了

相关文章
相关标签/搜索