Glide 源码(一)

Glide 源码

Glide是google开源的一款图片加载框架,注重性能和加载速度。本身采用流式Api便于操作。本文根据Glide源码,分析一下Glide的内部实现。源码基于glide 3.7

with()

Glide的使用从Glide.with(Context context)开始,with是Glide的一个静态方法,参数为context,内部Glide会根据传入的不同context进行不同的操作。

    public static RequestManager with(Context context) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(context);
}

RequestManagerRetriever用于生成RequestManager,跟进RequestManagerRetriever的get()方法:

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);
}

//以Activity举例
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        android.app.FragmentManager fm = activity.getFragmentManager();
        return fragmentGet(activity, fm);
    }
}

可以看到get方法根据不同的context种类进行不同的操作,如果是ApplicationContext或者在后台线程创建的Glide会默认走getApplicationManager()方法。

接下来进入fragmentGet()方法:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
    RequestManagerFragment current = getRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

getRequestManagerFragment方法使用默认的tag通过findFragmentByTag获取RequestManagerFragment。如果没有则新建一个返回。这里问什么要创建一个RequestManagerFragment呢?其实RequestManagerFragment是Fragment的一个子类,RequestManager是它的成员变量。Glide这里的做法很巧妙,通过创建一个与当前Activity绑定的没有布局的Fragment用于监听Activity的生命周期,并在一些特定时期调用RequestManager的方法。比如,Fragment实现了ComponentCallbacks2接口,有两个方法onTrimMemory()和onLowMemory()。用于在内存不足时调用RequestManager的方法用于释放内存。因为Glide内部对Activity的生命周期进行监听,在onDestory()的时候释放了资源并调用了RequestTacker的clearRequests()方法取消网络请求,防止内存泄漏。所以对于使用者来说不用手动的在onDestory()中对Glide进行操作。这也解释了为什么在子线程创建会传入ApplicationContext,使Glide与整个应用的生命周期保持一致。

注意到在获取RequestManager的时候有一个assertNotDestroyed(activity)方法:

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
        throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
    }
}

在实际开发中在网络比较慢的时候比如去服务器请求图片url比较慢,当请求过程中按下了返回键,url返回调用Glide加载时activity已经销毁,将会抛出异常。这里的解决思路是尽可能早的把RequestManager创建出来,比如可以在Activity的onCreate()方法或者Fragment的onAttach()方法进行RequestManager的初始化操作。

RequestManager manager = Glide.with(this);

load()

通过Glide.with()方法得到RequestManager后,调用RequestManager的load方法进行图片加载。

load()有多个重载方法,分别对应从uri、url、文件、资源id等地方进行加载。我们选取最常用的从url加载进行进一步分析。

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

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

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));
}

与从url加载类似,其他集中load()方法同样最后调用loadGeneric()方法,传入不同的class对象,构建不同的ModelLoader。loadGeneric()方法构建两个ModelLoader,新建一个DrawableTypeRequest并返回。ModelLoader在Glide中是一个比较重要的概念,作用是从原始数据源中取出数据。即把抽象的数据模型转化成具体的数据,一般为InputSteam,比如根据url网络请求。

实际上,Glide 在初始化的时候,对于每种类型的输入:String、int、Integer、File、Uri,都注册了能够将它们转化为 InputStream 和 ParcelFileDescriptor 的 ModelLoader,保存在HashMap中。这两个 buildxxxModelLoader() 方法实际上就是从 HashMap 中获取对应的 ModelLoader。在当前情景下,获取到的是 StreamStringLoader 和 FileDescriptorStringLoader。

buildxxxModelLoader内部实现都是一样的,都是先从缓存中取,如果取不到通过Factory创建一个并加入到缓存中,以buildStreamModelLoader()为例:

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);
}

public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
    ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
    if (result != null) {
        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 {
        cacheNullLoader(modelClass, resourceClass);
    }
    return result;
}

Glide.get(context).getLoaderFactory()工厂GenericLoaderFactory,调用工厂的buildModelLoader()方法,首先通过getCacheLoader方法判断缓存是否存在。如果不存在,同样从缓存中获取ModelLoaderFactory,调用build()方法,添加缓存并返回当前ModelLoader。因为当前的modelClass为url即为String.class,所以最终得到StreamStringLoader。

同理,得到FileDescriptorModelLoader,并最终构建出DrawableTypeRequest。回到RequestManager的load()方法,调用了DrawableTypeRequest的load()方法,DrawableTypeRequest继承自DrawableRequestBuilder,最终调用了DrawableRequestBuilder的父类GenericRequestBuilder的load()方法:

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

load()方法里只做了一些复制操作。至此load()方法告一段落,主要是根据数据源类型构建ModelLoader,并创建一个DrawableTypeRequest。

into()

load()方法返回了一个DrawableTypeRequest对象,into()是它的父类DrawableRequestBuilder的方法,内部调用了父类的into()方法,即GenericRequestBuilder。

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));
}

into()方法中,如果当前ImageView有设置ScaleType,则进行对应的裁剪操作。以applyCenterCrop()为例,发现GenericRequestBuilder的applyCenterCrop()由它的三个子类来实现:DrawableRequestBuilder、BitmapRequestBuilder、GifRequestBuilder。DrawableRequestBuilder上节我们提到了,BitmapRequestBuilder和GifRequestBuilder是怎么得到的呢?答案在DrawableTypeRequest里。DrawableTypeRequest里有两个方法asBitmap()、asGif()分别得到BitmapRequestBuilder和GifRequestBuilder。以常规的DrawableRequestBuilder的applyCenterCrop()为例:

@Override
void applyCenterCrop() {
    centerCrop();
}

public DrawableRequestBuilder<ModelType> centerCrop() {
    return transform(glide.getDrawableCenterCrop());
}

public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {
    super.transform(transformation);
    return this;
}

public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(
        Transformation<ResourceType>... transformations) {
    isTransformationSet = true;
    if (transformations.length == 1) {
        transformation = transformations[0];
    } else {
        transformation = new MultiTransformation<ResourceType>(transformations);
    }

    return this;
}

经过层层调用,最后到了GenericRequestBuilder的transform方法,transform方法只是一个简单的赋值操作,具体的转换操作不是在这里进行的。

回到into()方法调用了glide中的buildImageViewTarget()方法,构建一个ImageViewTarget:


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

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)");
    }
}

在ImageViewTargetFactory的buildTarget方法中,根据transcodedClass的类型构造出不同的ImageViewTarget,transcodedClass是GenericRequestBuilder的构造器传进来的,即上文提到的asBitmap()、asGif()。

得到ImageViewTarget后调用GenerocRequestBuilder中的into()的重载方法:


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

Glide 通过 View 的 setTag() 方法将特定的 View 和其对应的图片加载请求绑定在一起。这样做的好处是能够容易地判断 Target 所封装的 View 是否被复用,复用时先取消之前的请求,避免了不必要的请求,也能防止图片错位。

构建新的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) {
        if (isThumbnailBuilt) {
            throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, "
                    + "consider using clone() on the request(s) passed to thumbnail()");
        }
        // Recursive case: contains a potentially recursive thumbnail request builder.
        if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
            thumbnailRequestBuilder.animationFactory = animationFactory;
        }

        if (thumbnailRequestBuilder.priority == null) {
            thumbnailRequestBuilder.priority = getThumbnailPriority();
        }

        if (Util.isValidDimensions(overrideWidth, overrideHeight)
                && !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
                        thumbnailRequestBuilder.overrideHeight)) {
          thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
        }

        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
        // Guard against infinite recursion.
        isThumbnailBuilt = true;
        // Recursively generate thumbnail requests.
        Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
        isThumbnailBuilt = false;
        coordinator.setRequests(fullRequest, thumbRequest);
        return coordinator;
    } else if (thumbSizeMultiplier != null) {
        // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
        Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
        coordinator.setRequests(fullRequest, thumbnailRequest);
        return coordinator;
    } else {
        // Base case: no thumbnail.
        return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
    }
}

首先是与缩略图有关的逻辑,即是否调用thumbnail()方法,如果有缩略图构建两个request。如果没有,调用obtainRequest()方法,obtainRequest()方法构建了一个GenericRequest对象。接下来将target与request绑定起来,设置监听,调用RequestTracker的runRequest()方法。

RequestTracker是一个用来跟踪、取消或重启一个正在进行、完成或失败的请求。


public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
        request.begin();
    } else {
        pendingRequests.add(request);
    }
}

把请求加入请求队列中,如果tracker没有被停止,调用request的begin()方法,如果停止了,就加入到准备请求队列中。

Request的实现类GenericRequest中的begin()方法:


@Override
public void begin() {
    startTime = LogTime.getLogTime();
    if (model == null) {
        onException(null);
        return;
    }

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }

    if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
}

begin()方法主要确定请求图片的大小,即有没有调用override()方法,以及设置占位图。如果没有调用override方法,则调用target.getSize()方法(target父类ViewTarget):


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);
        }
    }
}

根据view的宽高以及LayoutParam得到图片宽高,调用SizeReadyCallback的onSizeReady()方法。GenericRequest实现了SizeReadyCallback接口,onSizeReady方法与重写了图片宽高所调用的onSizeReady()方法一致。


@Override
public void onSizeReady(int width, int height) {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    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;
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
}

计算过宽高之后通过loadProvider得到当前ModelLoader。那么loadProvider从哪来呢?在DrawableTypeRequest的构造函数看到一个buildProvider()方法:


buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                        GlideDrawable.class, null),
                glide, requestTracker, lifecycle);

private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
        ModelLoader<A, InputStream> streamModelLoader,
        ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
        Class<R> transcodedClass,
        ResourceTranscoder<Z, R> transcoder) {
    if (streamModelLoader == null && fileDescriptorModelLoader == null) {
        return null;
    }

    if (transcoder == null) {
        transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
    }
    DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
            resourceClass);
    ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
            fileDescriptorModelLoader);
    return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}

buildTranscoder()方法获取将GifBitmapWrapper转换成GlideDrawable的Transcoder,DataLoadProvider提供指定的类型的Data和Resource之间的编解码,
在这里获取的是ImageVideoWrapper与GlideDrawable之间的编解码provider。ImageVideoModelLoader是streamModelLoader和fileDescriptorModelLoader的封装。

回到onSizeReady()方法中,从loadProvider中获取到ImageVideoModelLoader以及ResourceTranscoder,并从ImageVideoModelLoader中获取到一个ImageVideoFetcher。调用Engine中的load()方法:


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();
    long startTime = LogTime.getLogTime();

    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);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
}

loadFromCache()、loadFromActiveResources()指从缓存中读取,以后会展开分析。接着往下分析,根据生成的key查询任务是否已经存在,如果存在,返回一个LoadStatus。LoadStatus指一个不再加载的请求。如果不存在,新建一个。并创建一个DecodeJob和EngineRunnable,调用EngineJob的start()方法

EngineJob 负责统一管理加载请求的 ResourceCallback,EngineJob 本身也实现了 ResourceCallback 接口,当加载请求完成时 EngineRunnable 回调 EngineJob 的 onResourceReady() 方法,EngineJob 在分发给所有的监听者。DecodeJob 的工作特别繁重,负责了 Resource 的所有解码工作,包括从 Data 解码和从缓存解码,同时承担了解码之后的转换和转码工作。

start()方法内部实现是把EngineRunnable提交给线程池,由线程池调用EngineRunnable的run()方法:

@Override
public void run() {
    if (isCancelled) {
        return;
    }

    Exception exception = null;
    Resource<?> resource = null;
    try {
        resource = decode();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Exception decoding", e);
        }
        exception = e;
    }

    if (isCancelled) {
        if (resource != null) {
            resource.recycle();
        }
        return;
    }

    if (resource == null) {
        onLoadFailed(exception);
    } else {
        onLoadComplete(resource);
    }
}


private Resource<?> decode() throws Exception {
    if (isDecodingFromCache()) {
        return decodeFromCache();
    } else {
        return decodeFromSource();
    }
}

private boolean isDecodingFromCache() {
    return stage == Stage.CACHE;
}

private Resource<?> decodeFromCache() throws Exception {
    Resource<?> result = null;
    try {
        result = decodeJob.decodeResultFromCache();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Exception decoding result from cache: " + e);
        }
    }

    if (result == null) {
        result = decodeJob.decodeSourceFromCache();
    }
    return result;
}

private Resource<?> decodeFromSource() throws Exception {
    return decodeJob.decodeFromSource();
}

默认的stage是从cache中取的,所以decode()方法中调用decodeFromCache(),如果在decodeFromCache中得到的result为空,会走onLoadFailed()逻辑:


private void onLoadFailed(Exception e) {
    if (isDecodingFromCache()) {
        stage = Stage.SOURCE;
        manager.submitForSource(this);
    } else {
        manager.onException(e);
    }
}

@Override
public void submitForSource(EngineRunnable runnable) {
    future = sourceService.submit(runnable);
}

如果从缓存中取不到,则更改策略,从source中取。第二次调用decodeFromSource():


private Resource<?> decodeFromSource() throws Exception {
    return decodeJob.decodeFromSource();
}

public Resource<Z> decodeFromSource() throws Exception {
    Resource<T> decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}

private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        final A data = fetcher.loadData(priority);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Fetched data", startTime);
        }
        if (isCancelled) {
            return null;
        }
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}

最终调用的是DecodeJob中的decodeSource()方法。通过fetcher的loadData()方法获取数据,这里的fetcher就是loadProvider中的ImageVideoFetcher:



@Override
 public ImageVideoWrapper loadData(Priority priority) throws Exception {
     InputStream is = null;
     if (streamFetcher != null) {
         try {
             is = streamFetcher.loadData(priority);
         } catch (Exception e) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
             }
             if (fileDescriptorFetcher == null) {
                 throw e;
             }
         }
     }
     ParcelFileDescriptor fileDescriptor = null;
     if (fileDescriptorFetcher != null) {
         try {
             fileDescriptor = fileDescriptorFetcher.loadData(priority);
         } catch (Exception e) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
             }
             if (is == null) {
                 throw e;
             }
         }
     }
     return new ImageVideoWrapper(is, fileDescriptor);
 }

从streamFetcher中获取InputStream,此时的streamFetcher是HttpUrlFetcher对象,调用它的loadData()方法:


@Override
public InputStream loadData(Priority priority) throws Exception {
   return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}

private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
       throws IOException {
   if (redirects >= MAXIMUM_REDIRECTS) {
       throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
   } else {
       // Comparing the URLs using .equals performs additional network I/O and is generally broken.
       // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
       try {
           if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
               throw new IOException("In re-direct loop");
           }
       } catch (URISyntaxException e) {
           // Do nothing, this is best effort.
       }
   }
   urlConnection = connectionFactory.build(url);
   for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
     urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
   }
   urlConnection.setConnectTimeout(2500);
   urlConnection.setReadTimeout(2500);
   urlConnection.setUseCaches(false);
   urlConnection.setDoInput(true);

   // Connect explicitly to avoid errors in decoders if connection fails.
   urlConnection.connect();
   if (isCancelled) {
       return null;
   }
   final int statusCode = urlConnection.getResponseCode();
   if (statusCode / 100 == 2) {
       return getStreamForSuccessfulRequest(urlConnection);
   } else if (statusCode / 100 == 3) {
       String redirectUrlString = urlConnection.getHeaderField("Location");
       if (TextUtils.isEmpty(redirectUrlString)) {
           throw new IOException("Received empty or null redirect url");
       }
       URL redirectUrl = new URL(url, redirectUrlString);
       return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
   } else {
       if (statusCode == -1) {
           throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
       }
       throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
   }


   private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
         throws IOException {
     if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
         int contentLength = urlConnection.getContentLength();
         stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
     } else {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
         }
         stream = urlConnection.getInputStream();
     }
     return stream;
 }
}

根据HttpUrlConnection获取InputStream,封装成ImageVideoWrapper并返回。回到decodeFromSourceData()方法:

private Resource<T> decodeFromSourceData(A data) throws IOException {
    final Resource<T> decoded;
    if (diskCacheStrategy.cacheSource()) {
        decoded = cacheAndDecodeSourceData(data);
    } else {
        long startTime = LogTime.getLogTime();
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded from source", startTime);
        }
    }
    return decoded;
}

首先进行缓存操作,然后从loadeProvider中获取Decoder,进行decode操作。这里得到的Decoder是GifBitmapWrapperDrawableTranscoder对象,调用它的decode()方法:


@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
    ByteArrayPool pool = ByteArrayPool.get();
    byte[] tempBytes = pool.getBytes();

    GifBitmapWrapper wrapper = null;
    try {
        wrapper = decode(source, width, height, tempBytes);
    } finally {
        pool.releaseBytes(tempBytes);
    }
    return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}

private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException {
    final GifBitmapWrapper result;
    if (source.getStream() != null) {
        result = decodeStream(source, width, height, bytes);
    } else {
        result = decodeBitmapWrapper(source, width, height);
    }
    return result;
}

private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes)
        throws IOException {
    InputStream bis = streamFactory.build(source.getStream(), bytes);
    bis.mark(MARK_LIMIT_BYTES);
    ImageHeaderParser.ImageType type = parser.parse(bis);
    bis.reset();

    GifBitmapWrapper result = null;
    if (type == ImageHeaderParser.ImageType.GIF) {
        result = decodeGifWrapper(bis, width, height);
    }
    // Decoding the gif may fail even if the type matches.
    if (result == null) {
        // We can only reset the buffered InputStream, so to start from the beginning of the stream, we need to
        // pass in a new source containing the buffered stream rather than the original stream.
        ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
        result = decodeBitmapWrapper(forBitmapDecoder, width, height);
    }
    return result;
}

private GifBitmapWrapper decodeGifWrapper(InputStream bis, int width, int height) throws IOException {
    GifBitmapWrapper result = null;
    Resource<GifDrawable> gifResource = gifDecoder.decode(bis, width, height);
    if (gifResource != null) {
        GifDrawable drawable = gifResource.get();
        // We can more efficiently hold Bitmaps in memory, so for static GIFs, try to return Bitmaps
        // instead. Returning a Bitmap incurs the cost of allocating the GifDrawable as well as the normal
        // Bitmap allocation, but since we can encode the Bitmap out as a JPEG, future decodes will be
        // efficient.
        if (drawable.getFrameCount() > 1) {
            result = new GifBitmapWrapper(null /*bitmapResource*/, gifResource);
        } else {
            Resource<Bitmap> bitmapResource = new BitmapResource(drawable.getFirstFrame(), bitmapPool);
            result = new GifBitmapWrapper(bitmapResource, null /*gifResource*/);
        }
    }
    return result;
}

内部调用了decodeStream()将InputStream转成图片。首先读取stream前两个字节判读是否为Gif图,如果是Gif,调用decodeGifWrapper(),如果不是调用decodeBitmapWrapper():


private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
    GifBitmapWrapper result = null;

    Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
    if (bitmapResource != null) {
        result = new GifBitmapWrapper(bitmapResource, null);
    }

    return result;
}

方法内部调用了bitmapDecoder的decode方法,生成一个Resource对象,并封装成GifBitmapWrapper。这里的bitmapDecoder实际是ImageVideoBitmapDecoder对象,调用它的decode方法,最终调用了Downsampler的decode()方法:


public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
    final ByteArrayPool byteArrayPool = ByteArrayPool.get();
    final byte[] bytesForOptions = byteArrayPool.getBytes();
    final byte[] bytesForStream = byteArrayPool.getBytes();
    final BitmapFactory.Options options = getDefaultOptions();

    RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
            is, bytesForStream);
    ExceptionCatchingInputStream exceptionStream =
            ExceptionCatchingInputStream.obtain(bufferedStream);

    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    try {
        exceptionStream.mark(MARK_POSITION);
        int orientation = 0;
        try {
            orientation = new ImageHeaderParser(exceptionStream).getOrientation();
        } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Cannot determine the image orientation from header", e);
            }
        } finally {
            try {
                exceptionStream.reset();
            } catch (IOException e) {
                if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Cannot reset the input stream", e);
                }
            }
        }

        options.inTempStorage = bytesForOptions;

        final int[] inDimens = getDimensions(invalidatingStream, bufferedStream, options);
        final int inWidth = inDimens[0];
        final int inHeight = inDimens[1];

        final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
        final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);

        final Bitmap downsampled =
                downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,
                        decodeFormat);

        final Exception streamException = exceptionStream.getException();
        if (streamException != null) {
            throw new RuntimeException(streamException);
        }

        Bitmap rotated = null;
        if (downsampled != null) {
            rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);

            if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
                downsampled.recycle();
            }
        }

        return rotated;
    } finally {
        byteArrayPool.releaseBytes(bytesForOptions);
        byteArrayPool.releaseBytes(bytesForStream);
        exceptionStream.release();
        releaseOptions(options);
    }
}

自此生成了需要的bitmap。

回到decodeFromSource()方法,接下来调用transformEncodeAndTranscode(decoded)方法:


private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
    long startTime = LogTime.getLogTime();
    Resource<T> transformed = transform(decoded);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transformed resource from source", startTime);
    }

    writeTransformedToCache(transformed);

    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transcoded transformed from source", startTime);
    }
    return result;
}

如果由transform,调用transform方法,接着把转换后的resource写入到缓存。经过一系列编解码,最终回到了EngineRunnable的run()方法,调用onLoadComplete():


private void onLoadComplete(Resource resource) {
    manager.onResourceReady(resource);
}

manager是一个EngineRunnableManager接口,它的实现类是EngineJob,进入EngineJob的onResourceReady()方法:


@Override
public void onResourceReady(final Resource<?> resource) {
    this.resource = resource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}

private void handleResultOnMainThread() {
     if (isCancelled) {
         resource.recycle();
         return;
     } else if (cbs.isEmpty()) {
         throw new IllegalStateException("Received a resource without any callbacks to notify");
     }
     engineResource = engineResourceFactory.build(resource, isCacheable);
     hasResource = true;

     // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
     // synchronously released by one of the callbacks.
     engineResource.acquire();
     listener.onEngineJobComplete(key, engineResource);

     for (ResourceCallback cb : cbs) {
         if (!isInIgnoredCallbacks(cb)) {
             engineResource.acquire();
             cb.onResourceReady(engineResource);
         }
     }
     // Our request is complete, so we can release the resource.
     engineResource.release();
 }

onResourceReady()中发出一条消息,在handleResultOnMainThread()中调用了ResourceCallback的onResourceReady()方法,GenericRequest实现了ResourceCallback:

@Override
public void onResourceReady(Resource<?> resource) {
    if (resource == null) {
        onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
                + " inside, but instead got null."));
        return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
        releaseResource(resource);
        onException(new Exception("Expected to receive an object of " + transcodeClass
                + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
                + " inside Resource{" + resource + "}."
                + (received != null ? "" : " "
                    + "To indicate failure return a null Resource object, "
                    + "rather than a Resource object containing null data.")
        ));
        return;
    }

    if (!canSetResource()) {
        releaseResource(resource);
        // We can't set the status to complete before asking canSetResource().
        status = Status.COMPLETE;
        return;
    }

    onResourceReady(resource, (R) received);
}

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();

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
                + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
    }
}


调用了target.onResourceReady(result, animation),target就是我们前面所提到的把ImageView封装成的ImageViewTarget:


@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);

以BitmapImageViewTarget为例:

@Override
protected void setResource(Bitmap resource) {
    view.setImageBitmap(resource);
}

最终图片显示出来。

参考文章

Glide源码解析(一):加载流程

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

推荐阅读更多精彩内容