Android源码学习-Glide源码浅析

2019-03-25  本文已影响0人  m1Ku

介绍

Glide是一个图片加载框架,它为我们封装了一系列链式调用的方法,方便我们指定加载的上下文Context、图片的来源,配置图片加载的占位符、图片缩放方式,以及内存磁盘缓存策略等的配置。简单使用如下。

Glide.with(this)
                .load(url)
                .into(ivGlide);

源码分析

基于Glide4.9.0

1 with方法:实例化RequestManager对象并且绑定Activity生命周期

从with方法开始切入源码,学习Glide的实现。

//1.
public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }
//2.
public static RequestManager with(Activity activity) {}
//3.
public static RequestManager with(FragmentActivity activity) {}
//4.
public static RequestManager with(android.app.Fragment fragment) {}
//5.
public static RequestManager with(Fragment fragment) {}

with有5个重载方法。从with方法上的注释我们可以得知:如果使用Context参数的重载方法,Glide并不会根据当前页面(如Activity或者Fragment)的生命周期来开始或者停止,而是会依赖Application层级。通常选用with方法的原则是看Glide加载的结果是在哪种上下文层级中使用。例如,如果资源是在子Fragment的View中使用,则就应该使用参数为Fragment的with方法,以此类推。

with中首先获取RequestManagerRetriever的单例对象,再通过它的get方法获取RequestManager对象

public RequestManager get(Context context) {
    if (context == null) {
        throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
        if (context instanceof FragmentActivity) {
            return get((FragmentActivity) context);
        } else if (context instanceof Activity) {
            return get((Activity) context);
        } else if (context instanceof ContextWrapper) {
            return get(((ContextWrapper) context).getBaseContext());
        }
    }
    return getApplicationManager(context);
}

在方法中判断Context的实例类型,分别调用对应的重载方法。以FragmentActivity类型为例看一下get方法:

public RequestManager get(FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm);
    }
}

如果在子线程中,则获取application层级的RequestManager。如果在主线程中,判断activity实例是否被销毁,如果没有被销毁,获取当前activity的FragmentManager传入supportFragmentGet方法中。

RequestManager supportFragmentGet(Context context, FragmentManager fm) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

getSupportRequestManagerFragment方法首先获取一个Fragment实例,实现如下

SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {
            current = new SupportRequestManagerFragment();
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}

先通过tag获取fragment,如果为空,再从pendingSupportRequestManagerFragments中获取。如果都没有的话,证明该activity界面还未添加过fragment,于是便通过new实例化该fragment,并将其添加到当前界面,最后返回该实例。

获取到current实例后,再回到supportFragmentGet方法中。从current中获取requestManager,如果requestManager为空,再实例化它,然后通过setRequestManager方法将其设置到current中。

从这里就可以看出requestManager和这个添加的fragment是绑定的,我们进一步可以猜测Glide就是通过监听这个添加的无界面的fragment来绑定声明周期的

1.1 Glide是具体如何绑定生命周期的?

SupportRequestManagerFragment的构造方法如下:

public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
}

// For testing only.
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
}

无参构造调用一个参数的构造方法,传入一个ActivityFragmentLifecycle类型的对象,ActivityFragmentLifecycle定义如下

class ActivityFragmentLifecycle implements Lifecycle {
    private final Set<LifecycleListener> lifecycleListeners =
            Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
    private boolean isStarted;
    private boolean isDestroyed;
    
    @Override
    public void addListener(LifecycleListener listener) {
        lifecycleListeners.add(listener);

        if (isDestroyed) {
            listener.onDestroy();
        } else if (isStarted) {
            listener.onStart();
        } else {
            listener.onStop();
        }
    }

    void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStart();
        }
    }

    void onStop() {
        isStarted = false;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStop();
        }
    }

    void onDestroy() {
        isDestroyed = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onDestroy();
        }
    }
}

该类实现了Lifecycle接口,并且实现了addListener方法,记住该方法接收LifecycleListener类型的对象,这个方法的参数类型很重要,等会儿会用到。

我们再看一下RequestManager的定义以及其构造方法:

requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
public class RequestManager implements LifecycleListener {
    //...
    public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        //...
        this.lifecycle = lifecycle;
        //...

        ConnectivityMonitor connectivityMonitor = factory.build(context,
                new RequestManagerConnectivityListener(requestTracker));

        if (Util.isOnBackgroundThread()) {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }
}

我们发现在初始化RequestManager时,传入了current.getLifecycle(),而这个对象就是上面分析的ActivityFragmentLifecycle对象。RequestManager实现了LifecycleListener接口,而上面分析到addListener的参数类型恰恰就是LifecycleListener类型的,于是在构造方法中它将其自身this传递了进去。

由于我们是要分析Glide是如何绑定生命周期的,所以在看完这两个对象的构造函数后,继续看一下这个fragment生命周期函数做了哪些事

@Override
public void onStart() {
    super.onStart();
    lifecycle.onStart();
}

@Override
public void onStop() {
    super.onStop();
    lifecycle.onStop();
}

@Override
public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
}

在生命周期函数中调用了ActivityFragmentLifecycle对象的对应方法,如

void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStart();
        }
    }

在该方法中遍历了lifecycleListeners调用了每个对象的生命周期方法,而该对象就是在RequestManager构造函数中添加的this即RequestManager本身,所以当fragment生命周期调用时,就会回调RequestManager中实现的对应生命周期方法,也就是完成了生命周期的绑定。

以上完成了with方法的分析,with方法做的工作主要是:创建了RequestManager对象,创建一个无界面的fragment并添加到当前界面,而RequestManager通过监听这个fragment的生命周期达到了绑定生命周期的效果。

2 Load方法:构建DrawableTypeRequest对象

下面继续分析load方法

load方法也有几个不同参数的重载方法,下面以String为参数的方法分析,该参数可以是图片的文件路径,uri或者url

public DrawableTypeRequest<String> load(String string) {
    return (DrawableTypeRequest<String>) fromString().load(string);
}

调用fromString()方法

public DrawableTypeRequest<String> fromString() {
    return loadGeneric(String.class);
}

这是一个空壳,转而调用loadGeneric方法

private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
    ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
    ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
            Glide.buildFileDescriptorModelLoader(modelClass, context);
    if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
        throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
                + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                + " Glide#register with a ModelLoaderFactory for your custom model class");
    }

    return optionsApplier.apply(
            new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                    glide, requestTracker, lifecycle, optionsApplier));
}

这个方法中有个新的对象

首先,ModelLoader的概念

ModelLoader是一个工厂接口,他可以将任意的复杂数据模型转化成具体的可以被解码成资源的数据类型。

看一下streamModelLoader的创建过程

ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
/**
     * A method to build a {@link ModelLoader} for the given model that produces {@link InputStream}s using a registered
     * factory.
     *
     * @see #buildModelLoader(Class, Class, android.content.Context)
     */
public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
        return buildModelLoader(modelClass, InputStream.class, context);
    }

public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
            Context context) {
         if (modelClass == null) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Unable to load null model, setting placeholder only");
            }
            return null;
        }
        return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
    }

buildStreamModelLoader方法的注释:使用注册的工厂,创建将给定的model转换为InputStream的ModelLoader。很明显这里的model为String.class类型。也就是创建的这个ModelLoader对象可以将String.class类型的model转化为InputStream。

在buildModelLoader方法中,获取loaderFactory工厂类,调用它的buildModelLoader方法创建ModelLoader对象返回

public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
    ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
    if (result != null) {
        // We've already tried to create a model loader and can't with the currently registered set of factories,
        // but we can't use null to demonstrate that failure because model loaders that haven't been requested
        // yet will be null in the cache. To avoid this, we use a special signal model loader.
        if (NULL_MODEL_LOADER.equals(result)) {
            return null;
        } else {
            return result;
        }
    }

    final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
    if (factory != null) {
        result = factory.build(context, this);
        cacheModelLoader(modelClass, resourceClass, result);
    } else {
        // We can't generate a model loader for the given arguments with the currently registered set of factories.
        cacheNullLoader(modelClass, resourceClass);
    }
    return result;
}

调用getFactory方法

private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
    Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
    ModelLoaderFactory/*T, Y*/ result = null;
    if (resourceToFactories != null) {
        result = resourceToFactories.get(resourceClass);
    }

    if (result == null) {
        for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
            if (registeredModelClass.isAssignableFrom(modelClass)) {
                Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
                        modelClassToResourceFactories.get(registeredModelClass);
                if (currentResourceToFactories != null) {
                    result = currentResourceToFactories.get(resourceClass);
                    if (result != null) {
                        break;
                    }
                }
            }
        }
    }

    return result;
}

遍历modelClassToResourceFactories这个map的key,查找对应传入model类型的工厂类的map,然后从该map中获得工厂,该map中保存的就是上面所说的注册的工厂。

ModelLoader的工厂是如何注册的,保存工厂的map是如何赋值的呢?

我们注意到在Glide的构造方法中调用了一些register方法:

这里还是以String.class类型参数的来看

//...
register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
//...

register方法的实现

public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {
    ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory);
    if (removed != null) {
        removed.teardown();
    }
}

这里调用了loaderFactory的register方法

public synchronized <T, Y> ModelLoaderFactory<T, Y> register(Class<T> modelClass, Class<Y> resourceClass,
        ModelLoaderFactory<T, Y> factory) {
    cachedModelLoaders.clear();

    Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
    if (resourceToFactories == null) {
        resourceToFactories = new HashMap<Class/*Y*/, ModelLoaderFactory/*T, Y*/>();
        modelClassToResourceFactories.put(modelClass, resourceToFactories);
    }

    ModelLoaderFactory/*T, Y*/ previous = resourceToFactories.put(resourceClass, factory);

    if (previous != null) {
        // This factory may be being used by another model. We don't want to say it has been removed unless we
        // know it has been removed for all models.
        for (Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> factories : modelClassToResourceFactories.values()) {
            if (factories.containsValue(previous)) {
                previous = null;
                break;
            }
        }
    }
    return previous;
}

在这个方法中为model和对应的ModelLoader做了关联,并且完成了对modelClassToResourceFactories这个map属性的赋值。

我们继续回到buildModelLoader方法中,此时就得到了工厂类:如下

/**
 * The default factory for {@link com.bumptech.glide.load.model.stream.StreamUrlLoader}s.
 */
public static class Factory implements ModelLoaderFactory<URL, InputStream> {
    @Override
    public ModelLoader<URL, InputStream> build(Context context, GenericLoaderFactory factories) {
        return new StreamUrlLoader(factories.buildModelLoader(GlideUrl.class, InputStream.class));
    }

    @Override
    public void teardown() {
        // Do nothing.
    }
}

public StreamUrlLoader(ModelLoader<GlideUrl, InputStream> glideUrlLoader) {
    super(glideUrlLoader);
}

调用factory.build方法通过工厂构建对应的ModelLoader实例,这里是StreamUrlLoader对象。这样loadGeneric方法中的streamModelLoader对象就构建好了,该方法中的fileDescriptorModelLoader对象构造也算是相同的道理。如下,最后实例化了DrawableTypeRequest对象返回。

return optionsApplier.apply(
        new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                glide, requestTracker, lifecycle, optionsApplier));

fromString()流程跟完了,我们回到分析load方法开始的地方,调用fromString构造好的DrawableTypeRequest对象的load方法,该load方法在其父类DrawableRequestBuilder中:

@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
    super.load(model);
    return this;
}

继续调用父类GenericRequestBuilder的load方法

public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
    this.model = model;
    isModelSet = true;
    return this;
}

在该方法中设置了用来请求图片的地址,并将isModelSet标志位置为true。

3 into方法:构建Target对象并获取资源加载在Target上

调用DrawableTypeRequest父类DrawableRequestBuilder的into方法

@Override
public Target<GlideDrawable> into(ImageView view) {
    return super.into(view);
}

继续调用父类GenericRequestBuilder的into方法

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    if (view == null) {
        throw new IllegalArgumentException("You must pass in a non null View");
    }

    if (!isTransformationSet && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                applyCenterCrop();
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                applyFitCenter();
                break;
            //$CASES-OMITTED$
            default:
                // Do nothing.
        }
    }
    return into(glide.buildImageViewTarget(view, transcodeClass));
}

上面获取ImageView的scaleType做相应的处理,然后执行到return的into方法,该方法中调用了glide的buildImageViewTarget方法:

<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}

调用工厂类的buildTarget方法

public class ImageViewTargetFactory {

    @SuppressWarnings("unchecked")
    public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
        if (GlideDrawable.class.isAssignableFrom(clazz)) {
            return (Target<Z>) new GlideDrawableImageViewTarget(view);
        } else if (Bitmap.class.equals(clazz)) {
            return (Target<Z>) new BitmapImageViewTarget(view);
        } else if (Drawable.class.isAssignableFrom(clazz)) {
            return (Target<Z>) new DrawableImageViewTarget(view);
        } else {
            throw new IllegalArgumentException("Unhandled class: " + clazz
                    + ", try .as*(Class).transcode(ResourceTranscoder)");
        }
    }
}

这里判断clazz的类型构建对应的target。而clazz是在初始化DrawableTypeRequest对象时指定的:

DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
        ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
        RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
    super(context, modelClass,
            buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                    GlideDrawable.class, null),
            glide, requestTracker, lifecycle);
    this.streamModelLoader = streamModelLoader;
    this.fileDescriptorModelLoader = fileDescriptorModelLoader;
    this.optionsApplier = optionsApplier;
}

如上,是GlideDrawable.class类型,所以工厂构建了GlideDrawableImageViewTarget类型的target对象。将这个target对象传入到into方法中

/**
 * Set the target the resource will be loaded into.
 *
 * @see Glide#clear(com.bumptech.glide.request.target.Target)
 *
 * @param target The target to load the resource into.
 * @return The given target.
 */
public <Y extends Target<TranscodeType>> Y into(Y target) {
    Util.assertMainThread();
    if (target == null) {
        throw new IllegalArgumentException("You must pass in a non null Target");
    }
    if (!isModelSet) {
        throw new IllegalArgumentException("You must first set a model (try #load())");
    }

    Request previous = target.getRequest();

    if (previous != null) {
        previous.clear();
        requestTracker.removeRequest(previous);
        previous.recycle();
    }

    Request request = buildRequest(target);
    target.setRequest(request);
    lifecycle.addListener(target);
    requestTracker.runRequest(request);

    return target;
}

该方法中首先确保在主线程中执行,判断target是否为空,以及是否已经调用load方法设置了url。然后从target获取已经存在的Request,如果不为空将其清除并从requestTracker中移除,以避免图片加载错乱。与listview的getView方法的convertView.setTag一样,这里将request作为tag设置给target包装的view(这里具体可以在下面的target.setRequest实现看到)。

调用buildRequest构建一个request请求对象

private Request buildRequest(Target<TranscodeType> target) {
    if (priority == null) {
        priority = Priority.NORMAL;
    }
    return buildRequestRecursive(target, null);
}

private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
    if (thumbnailRequestBuilder != null) {
    //...
    } else if (thumbSizeMultiplier != null) {
    //...
    } else {
        // Base case: no thumbnail.
        return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
    }
}

buildRequestRecursive上面两个分支是存在缩略情况的,这里省略。看最后一个分支,obtainRequest

private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
        RequestCoordinator requestCoordinator) {
    return GenericRequest.obtain(
            loadProvider,
            model,
            signature,
            context,
            priority,
            target,
            sizeMultiplier,
            placeholderDrawable,
            placeholderId,
            errorPlaceholder,
            errorId,
            fallbackDrawable,
            fallbackResource,
            requestListener,
            requestCoordinator,
            glide.getEngine(),
            transformation,
            transcodeClass,
            isCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
}

这里构建一个GenericRequest对象返回。

构建完request后,将request设置给target

@Override
public void setRequest(Request request) {
    setTag(request);
}
private void setTag(Object tag) {
        if (tagId == null) {
            isTagUsedAtLeastOnce = true;
            view.setTag(tag);
        } else {
            view.setTag(tagId, tag);
        }
    }

而这里就是将request作为tag设置给了target中的view。

由于target对象继承了LifecycleListener接口,这里将其添加到lifecycle,target本身也可以感知生命周期。

最后就调用requestTracker类的runRequest方法执行请求

/**
 * Starts tracking the given request.
 */
public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
        request.begin();
    } else {
        pendingRequests.add(request);
    }
}

而requestTracker类是专门用来跟踪,取消,以及重新开始请求的一个请求管理类。这里首先将请求添加到requests集合中,然后判断如果当前是暂停状态,就将当前请求添加到等待执行的请求队列,否者就调用begin方法开始请求

@Override
public void begin() {
    //...
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }

    if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
    }
    //...
}

begin方法中将Status置为WAITING_FOR_SIZE(等待尺寸状态),然后判断使用Glide时是否调用了override方设置了宽高,如果没有设置宽高,将this传递到getSize方法中获取宽高,this即GenericRequest,它实现了SizeReadyCallback接口,高宽准备好会回调这个接口。下面的if语句判断当前是未完成并且未失败状态时,设置了placeHolder占位符图片。

@Override
public void getSize(SizeReadyCallback cb) {
    sizeDeterminer.getSize(cb);
}

public void getSize(SizeReadyCallback cb) {
            int currentWidth = getViewWidthOrParam();
            int currentHeight = getViewHeightOrParam();
            if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
                cb.onSizeReady(currentWidth, currentHeight);
            } else {
                // We want to notify callbacks in the order they were added and we only expect one or two callbacks to
                // be added a time, so a List is a reasonable choice.
                if (!cbs.contains(cb)) {
                    cbs.add(cb);
                }
                if (layoutListener == null) {
                    final ViewTreeObserver observer = view.getViewTreeObserver();
                    layoutListener = new SizeDeterminerLayoutListener(this);
                    observer.addOnPreDrawListener(layoutListener);
                }
            }
        }

如上,宽高准备好后调用cb.onSizeReady,回到GenericRequest的回调方法中

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

    width = Math.round(sizeMultiplier * width);
    height = Math.round(sizeMultiplier * height);

    ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
    final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

    if (dataFetcher == null) {
        onException(new Exception("Failed to load model: \'" + model + "\'"));
        return;
    }
    ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadedFromMemoryCache = true;
    loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
            priority, isMemoryCacheable, diskCacheStrategy, this);
    loadedFromMemoryCache = resource != null;
}

回调方法中先将状态置为RUNNING运行中,再获取到dataFetcher和transcoder对象,调用engine.load方法,Engine是负责开始加载以及管理活动和缓存的资源的类。

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
        DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
        Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
    Util.assertMainThread();

    final String id = fetcher.getId();
    EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
            loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
            transcoder, loadProvider.getSourceEncoder());

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        cb.onResourceReady(active);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from active resources", startTime, key);
        }
        return null;
    }

    EngineJob current = jobs.get(key);
    if (current != null) {
        current.addCallback(cb);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }

    EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
    DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
            transcoder, diskCacheProvider, diskCacheStrategy, priority);
    EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(runnable);

    return new LoadStatus(cb, engineJob);
}

load方法根据给定的参数来加载资源。根据给定参数构建一个key,首先从内存缓存中获取资源,如果有的话调用onResourceReady的回调,如果没有则从活动的使用过得资源中获取,如果没有则看是否存在正在进行的加载,如果有的话将cb回调添加进去,以上如果都没有的话,则构建一个runnable开始新的加载。不管哪一步获取到数据,都会回调GenericRequest中的onResourceReady方法

@Override
public void onResourceReady(Resource<?> resource) {
    //...
    Object received = resource.get();
    //..
    onResourceReady(resource, (R) received);
}

调用onResourceReady重载方法

private void onResourceReady(Resource<?> resource, R result) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
            isFirstResource)) {
        GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
        target.onResourceReady(result, animation);
    }
    notifyLoadSuccess();
}

将Status置为COMPLETE完成状态,调用target的onResourceReady方法

@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
    if (!resource.isAnimated()) {
        float viewRatio = view.getWidth() / (float) view.getHeight();
        float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
        if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
                && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
            resource = new SquaringDrawable(resource, view.getWidth());
        }
    }
    super.onResourceReady(resource, animation);
    this.resource = resource;
    resource.setLoopCount(maxLoopCount);
    resource.start();
}

调用父类的onResourceReady

@Override
public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
    if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
        setResource(resource);
    }
}

protected abstract void setResource(Z resource);

setResource为抽象由子类实现,回到子类

@Override
protected void setResource(GlideDrawable resource) {
    view.setImageDrawable(resource);
}

这样,资源就成功设置到view上了。

上一篇下一篇

猜你喜欢

热点阅读