Glide的源码解析(一)(附方法调用图)

前言

上一篇博客讲了Glide的基本使用,知其然,也要知其所以然,这篇博客一起来学习Glide的源码。如果不知道Glide的基本使用,可以看上一篇博客:http://blog.csdn.net/luofen521/article/details/71210005

该博客也是基于郭霖大侠的Glide源码分析总结而得,算是自己做的笔记,郭大侠的博客传送门:http://blog.csdn.net/guolin_blog/article/details/53939176

问题

在没阅读Glide源码之前,我们带着下面几个问题去阅读源码,希望在阅读源码的过程中可以解决:

  1. Glide图片是用什么来下载的?HttpClient还是HttpURLConnection?亦或OKHttp?
  2. Glide图片是通过怎么解码的?是我们通常使用的BitmapFactory.decodeXXX方法么?
  3. Glide下载好图片以后,是怎么加载到ImageView上的?
  4. Glide怎么实现缓存的?是LruCache和DiskLruCache么?
  5. Glide的线程是怎么管理的?几个核心线程?几个最大线程?有最大任务数的限制么?
  6. Glide是怎么支持Gif图的?是通过Movie对象么?

源码版本

不同版本的Glide源码有些出入,该博客基于Glide3.7.0版本,来分析Glide如何在主线程中加载一张网络图片的,由于篇幅问题,该博客不考虑线程、缓存等流程。

源码解析

如何阅读源码:抽丝剥茧、点到即止。
Glide的流程过于复杂,其中的接口很多,为了方便阅读,强烈推荐下载方法调用流程图来对照着源码看,Pdf高清无码链接:http://download.csdn.net/detail/luofen521/9834616
Glide的源码解析(一)(附方法调用图)_第1张图片

从上一篇博客可知,Glide加载图片的流程就是先with,再load,最后into

Glide.with(context).load(imageUrl).into(imageView);

那我们顺着这条主线往下走

1. Glide.with()

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

public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

public static RequestManager with(FragmentActivity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

public static RequestManager with(Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

该方法首先调用了 RequestManagerRetriever的get无参方法,并返回一个 RequestManagerRetriever实例,该实例是单例的,代码如下:

private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();

public static RequestManagerRetriever get() {
    return INSTANCE;
}

然后调用其get的有参对象,得到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);
}

private RequestManager getApplicationManager(Context context) {
    if (applicationManager == null) {
        synchronized (this) {
            if (applicationManager == null) {
                applicationManager = new RequestManager(context.getApplicationContext(),
                        new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
            }
        }
    }
    return applicationManager;
}

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

public RequestManager get(Fragment fragment) {
    if (fragment.getActivity() == null) {
        throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread()) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        FragmentManager fm = fragment.getChildFragmentManager();
        return supportFragmentGet(fragment.getActivity(), fm);
    }
}

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

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(android.app.Fragment fragment) {
    if (fragment.getActivity() == null) {
        throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        android.app.FragmentManager fm = fragment.getChildFragmentManager();
        return fragmentGet(fragment.getActivity(), fm);
    }
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
            current = new RequestManagerFragment();
            pendingRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}

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

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

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

with方法可以分为两类,一类是参数为Application,一类是参数为非Appliction

参数为Application时,调用的是with(Context context)方法,可知,在其方法里直接调getApplicationManager(context)方法,可以看到,在getApplicationManager方法中,就是直接创建了一个RequestManager并返回,在构建RequestManager对象时,传入了ApplicationLifecycle对象,也就是说,当with方法传入的是Application时,Glide加载图片的生命周期和应用的生命周期一致,当退出应用时,图片停止加载。

参数为非Application时,调用的是with(Activity/Fragment)方法,在其方法里调用了fragmentGet/supportFragmentGet方法,而fragmentGet/supportFragmentGet方法中会先去调用getRequestManagerFragment/getSupportRequestManagerFragment方法去创建RequestManagerFragment/SupportRequestManagerFragment,并添加到Activity/Fragment上去,然后去创建一个RequestManager,在构建RequestManager时,会传入current.getLifeCycle,其实就是ActivityFragmentLifeCycle对象。也就是说,当with方法传入的是Activity或者Fragment时,会创建一个隐藏的Fragment加载到Activity/Fragment上,用于保证Glide加载图片的生命周期和Actiivty/Fragment一致,当退出Activity/Fragment时,图片停止加载。

这时候Glide.with()方法就完成了,它的主要作用是根据with的参数类型,创建一个RequestManager对象,在RequestManager的构造方法中,会调用Glide.get方法,在这个方法里会初始化线程池、缓存、Engin对象和Glide对象,等下篇讲线程池博客时再详细展开。这里要记住的就是RequestManager对象持有了不同的LifeCycle对象, 用于控制Glide加载图片的生命周期。

2.load()

由于Glide.with返回的是RequestManager,则需要到RequestManager类中查看load源码

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

load方法直接调用了fromString方法,然后用返回值调用了load方法,下面看看fromString方法

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

而fromString方法直接调用了loadGeneric 方法并返回,下面看看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);

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

这里调用了Glide.buildStreamModelLoader和Glide.buildFileDescriptorModelLoader去创建了两个ModelLoader,用于后续的图片加载,其中Glide.buildStreamModelLoader返回的是StreamStringLoader,至于为什么返回StreamStringLoader,可以从Glide的构造方法中找到原因。然后直接构建出了一个DrawableTypeRequest,这里用到了之前返回的StreamStringLoader,最后调用了OptionsApplier.apply方法,返回了一个DrawableTypeRequest对象。

这里需要注意的是构建出DrawableTypeRequest的步骤,其中初始化了很多后续步骤需要使用到的数据。

DrawableTypeRequest(Class modelClass, ModelLoader streamModelLoader,
        ModelLoader 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;
}

在DrawableTypeRequest的构造方法里,调用了buildProvider方法,并把返回值传入到了DrawableTypeRequest的父类构造方法当中。先看看buildProvider方法:

private static  FixedLoadProvider buildProvider(Glide glide,
        ModelLoader streamModelLoader,
        ModelLoader fileDescriptorModelLoader, Class resourceClass,
        Class transcodedClass,
        ResourceTranscoder transcoder) {
    if (streamModelLoader == null && fileDescriptorModelLoader == null) {
        return null;
    }

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

这里需要注意的是glide.buildTranscoder方法,它返回了一个GifBitmapWrapperDrawableTranscoder对象,用于后续图片格式的转换;通过glide.buildDataProvider得到一个DataLoadProvider对象;通过StreamStringLoader包装出来一个ImageVideoModelLoader对象,最后创建一个FixedLoadProvider对象,并把之前创建的三个对象传入构造方法中,最后把FixedLoadProvider对象返回。

回到loadGeneric方法中可知,返回的是一个DrawableTypeRequest对象,即fromString方法返回的是DrawableTypeRequest对象,在之前RequestManager中的load方法调用formString().load(),则是调用DrawableTypeRequest中的load方法,但是发现DrawableTypeRequest中并没有load方法,原来是在其父类DrawableRequestBuilder中,下面看看DrawableRequestBuilder中的load方法。

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

这里没有多余的逻辑,只是调用了父类中的load方法,并返回了this,最后看看其父类GenericRequestBuilder中的load方法

public GenericRequestBuilder load(ModelType model) {
    this.model = model;
    isModelSet = true;
    return this;
}

到这里,RequestManager中的load方法就结束了,可知,最后返回的是一个DrawRequestBuilder对象。

3. into()

因为RequestManager类中的load方法返回了DrawableRequestBuilder对象,则到DrawableRequestBuilder中看into方法,代码如下:

public Target into(ImageView view) {
    return super.into(view);
}

没有什么逻辑,直接调用父类的into方法,那我们看下其父GenericRequestBuilder的into方法,代码如下:

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

先看第一行,这里调用了Util.assertMainThread方法,用于判断当前线程是否是主线程,我们看看其中的逻辑:

public static void assertMainThread() {
    if (!isOnMainThread()) {
        throw new IllegalArgumentException("You must call this method on the main thread");
    }
}

如果不是主线程,就直接抛出异常。也就是说,使用Glide加载图片,必须要在主线程。

然后可以直接看into方法的最后一行,调用了into的重载方法,不过它的参数是通过Glide的buildImageViewTarget方法来构建出来的,我们先看看这个方法的逻辑,代码如下:

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

其实就是调用了一个ImageViewTargetFactory的buildTarget方法,并把返回值返回,从名字可以看出,该类是一个构建ImageViewTarget对象的工厂类,代码如下:

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

一般来说,就是返回GlideDrawableImageViewTarget对象,如果在into方法之前,调用了asBitmap方法,则是返回BitmapImageViewTarget对象。
再回到GenericRequestBuilder类中的into方法,glide.buildImageViewTarget方法返回了一个GlideDrawableImageViewTarget对象,接下来看GenericRequestBuilder类中into(Target)这个重载方法

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

在这个方法里,调用了buildRequest来得到Request对象,先看下buildRequest的代码,如下:

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

private Request buildRequestRecursive(Target 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);
    }
}

private Request obtainRequest(Target 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);
}

这里逻辑很简单,buildRequest中调用了buildRequestRecursive,而buildRequestRecursive调用了obtainRequest方法,在obtainRequest方法里,直接调用了GenericRequest.obtain方法,并返回,接下来,看一下GenericRequest的obtaion方法,如下:

public static  GenericRequest obtain(
        LoadProvider loadProvider,
        A model,
        Key signature,
        Context context,
        Priority priority,
        Target target,
        float sizeMultiplier,
        Drawable placeholderDrawable,
        int placeholderResourceId,
        Drawable errorDrawable,
        int errorResourceId,
        Drawable fallbackDrawable,
        int fallbackResourceId,
        RequestListenersuper A, R> requestListener,
        RequestCoordinator requestCoordinator,
        Engine engine,
        Transformation transformation,
        Class transcodeClass,
        boolean isMemoryCacheable,
        GlideAnimationFactory animationFactory,
        int overrideWidth,
        int overrideHeight,
        DiskCacheStrategy diskCacheStrategy) {
    @SuppressWarnings("unchecked")
    GenericRequest request = (GenericRequest) REQUEST_POOL.poll();
    if (request == null) {
        request = new GenericRequest();
    }
    request.init(loadProvider,
            model,
            signature,
            context,
            priority,
            target,
            sizeMultiplier,
            placeholderDrawable,
            placeholderResourceId,
            errorDrawable,
            errorResourceId,
            fallbackDrawable,
            fallbackResourceId,
            requestListener,
            requestCoordinator,
            engine,
            transformation,
            transcodeClass,
            isMemoryCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
    return request;
}

Glide中的Request是通过Queue来管理的,先从队列里出队一个GenericRequest对象,它实现了Request接口,如果为空就创建一个,然后完成初始化,并返回。
然后返回到GenericRequestBuilder中的into(Target)方法,buildRequest返回了一个GenericRequest对象,然后调用了RequestTracker.runRequest(Request)方法,我们来看看这个方法

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

这里调用了request对象的begin方法,request就是之前buildRequest方法返回的GenericRequest对象,接下来,看GenericRequest中的begin方法:

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

这里先判断了model是否为null,model其实就是加载的资源,这里就是url,如果url无效,则调用了onException方法,接下来看onException方法;

public void onException(Exception e) {
    if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "load failed", e);
    }
    status = Status.FAILED;
    //TODO: what if this is a thumbnail request?
    if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
        setErrorPlaceholder(e);
    }
}

private void setErrorPlaceholder(Exception e) {
    if (!canNotifyStatusChanged()) {
        return;
    }
    Drawable error = model == null ? getFallbackDrawable() : null;
    if (error == null) {
      error = getErrorDrawable();
    }
    if (error == null) {
        error = getPlaceholderDrawable();
    }
    target.onLoadFailed(e, error);
}

在onException中直接调用了setErrorPlaceholder方法,而setErrorPlaceholder方法中调用了target的onLoadFailed方法,target就是之前创建的GlideDrawableImageViewTarget对象,接下来看它里面的onLoadFailed方法,发现没有这个方法,但是在父类ImageViewTarge中发现了onLoadFailed方法,如下:

public void onLoadFailed(Exception e, Drawable errorDrawable) {
    view.setImageDrawable(errorDrawable);
}

代码很简单,直接给ImageView设置加载图片失败时的占位图,这就完成了当图片链接无效时,显示图片加载失败占位符的逻辑。GenericRequest中的begin方法中的target.onLoadStarted方法,显示图片加载成功之前的占位符,也是同样的逻辑。

回到GenericRequest中的begin方法中,如果url有效,且在into之前没有调用override()方法指定宽高,则会调用target的getSize参数,并把当前对象,就是GenericRequest对象作为参数传递过去了,这个target就是之前glide.buildImageViewTarget得到的GlideDrawableImageViewTarget对象,那我们看看GlideDrawableImageViewTarget类中是否有getSize方法,发现没有,则从其父类ImageViewTarget中寻找getSize方法,发现也没有,只有从ImageViewTarget的父类ViewTarget中寻找getSize方法,果不其然,getSize方法就是在ViewTarget中,方法如下:

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

这里直接调用了sizeDeterminer的getSize方法,SizeDeterminer其实就是ViewTarget的一个内部类,我们来看看SizeDeterminer中的getSize方法,代码如下:

public void getSize(SizeReadyCallback cb) {
    int currentWidth = getViewWidthOrParam();
    int currentHeight = getViewHeightOrParam();
    if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
    } else {

        if (!cbs.contains(cb)) {
            cbs.add(cb);
        }
        if (layoutListener == null) {
            final ViewTreeObserver observer = view.getViewTreeObserver();
            layoutListener = new SizeDeterminerLayoutListener(this);
            observer.addOnPreDrawListener(layoutListener);
        }
    }
}

这里直接调用了cb的onSizeReady方法,cb是SizeReadyCallback对象,那是从哪里传过来的呢?还记得tagert.getSize(this)这句代码吗?其实就是这个this,也就是GenericRequest对象,来看看GenericRequest的定义:

public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {

所以调用的就是GenericRequest的onSizeReady方法,接下来我们看看这个方法:

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 modelLoader = loadProvider.getModelLoader();
    final DataFetcher dataFetcher = modelLoader.getResourceFetcher(model, width, height);
    if (dataFetcher == null) {
        onException(new Exception("Failed to load model: \'" + model + "\'"));
        return;
    }
    ResourceTranscoder transcoder = loadProvider.getTranscoder();
    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));
    }
}

这里代码比较复杂,先看第8行代码,这里调用的是loadProvider的getModelLoader方法,那loadProvider是个什么对象呢?它其实就是在load方法中创建的FixLoadProvider对象,则这里调用的getModelLoader方法得到的就是load方法时,创建的ImageVideoModelLoader对象。
然后看第9行代码,则是调用的ImageVideoModelLoader类中的getResourceFetcher方法,代码如下:

@Override
public DataFetcher getResourceFetcher(A model, int width, int height) {
    DataFetcher streamFetcher = null;
    if (streamLoader != null) {
        streamFetcher = streamLoader.getResourceFetcher(model, width, height);
    }
    DataFetcher fileDescriptorFetcher = null;
    if (fileDescriptorLoader != null) {
        fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
    }

    if (streamFetcher != null || fileDescriptorFetcher != null) {
        return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
    } else {
        return null;
    }
}

直接调用了streamLoader的getResourceFetcher方法,这里的streamLoader是load方法中创建的StreamStringLoader对象,这里返回的是一个HttpUrlFetcher对象,然后把HttpUrlFetcher作为参数构造出ImageVideoFetcher对象,并返回

onSizeReady方法中的第14行代码,通过loadProvider调用getTranscoder()方法,得到的是load方法中创建的GifBitmapWrapperDrawableTranscoder对象

onSizeReady方法中第16代码,调用了engine.load方法,其中参数有前面得到的ImageVideoFetcher对象、GifBitmapWrapperDrawableTranscoder对象、FixedLoadProvider对象和this(GenericRequest对象)。engine是一个Engine对象,下面我们来看看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);
}

第38行,调用了一个EngineJobFactory的build方法,创建了一个EngineJob对象
第39行,直接创建了一个DecodeJob对象
第41行,通过之前创建的EngineJob和DecodeJob构建出了一个EngineRunnable对象,EngineRunnale实现了Runnable接口
第43行,调用EngineJob的addCallback方法,把cb加入到EngineJob的回调集合中,那似曾相识的cb是什么对象呢?就是之前提到的GenericRequest,它实现了ResourceCallback接口
第44行,调用了EngineJob的start方法,并把EngineRunnable对象传入进去,可以看出,重头戏要来了。
接下来看EngineJob的start方法:

public void start(EngineRunnable engineRunnable) {
    this.engineRunnable = engineRunnable;
    future = diskCacheService.submit(engineRunnable);
}

diskCacheService是一个Executorservice对象,这里直接调用了它的submit方法去执行EngineRunnable,接下来,看看EngineRunnable的run方法,注意这个方法已经是在子线程中运行了

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

    Exception exception = null;
    Resource> resource = null;
    try {
        resource = decode();
    } catch (Exception e) {
        exception = e;
    }

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

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

第10行,这里是调用了decode方法,最后返回了一个Resource的对象
第23行,这是当前面decode方法的返回值为null时,调用了onLoadFiled方法,和之前url无效,展示加载图片失败时的占位符
第25行,这是当decode方法的返回值不为null时,调用了onLoadComplete方法,顾名思义,就是对图片加载成功后对处理逻辑
显而易见,run方法中的逻辑就是调用decode方法得到图片资源,然后根据是否成功地得到图片资源,分别调用onLoadFailed方法和onLoadComplete方法对图片加载结果进行响应处理。
下面先来看本类中的decode方法:

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

这里先不管缓存逻辑,则调用decodeFromSource方法,并返回,下面看看decodeFromSource方法

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

直接调用了decodeJob的decodeFromSource方法,decodeJob就是在Engine的load方法中创建的DecodeJob,下面看看DecodeJob中的decodeFromSource

public Resource decodeFromSource() throws Exception {
    Resource decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}

第2行,调用了decodeSource方法,去得到图片资源,返回了一个Resource对象,这个跟返回值Resource是不是有什么千丝万缕的联系呢?这就要说到第3行的transfromEncodeAndTranscode方法了,这个方法接受了一个Resource参数,然后返回了一个Resource参数,没错,这个方法就是用来转换的,就是把下载的图片资源类型转换成一个可供展示的图片资源类型。至于Z和T的具体类型,下面会讲到
先看decodeSource方法:

private Resource decodeSource() throws Exception {
    Resource 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;
}

第5行,是用来真正进行下载图片逻辑,返回的是一个ImageVideoWrapper对象,这个对象里包装了图片的InputStream
第12行,是用来解析前面返回的ImageVideoWrapper,返回值是一个GitfBitmapWrapperResource对象,里面包装了Bitmap
先来看第5行代码,调用了fetcher.loadData方法,那fetcher是什么东西呢?fetcher其实就是构建EngineJob传入的ImageVideoFetcher对象,我们先来看看ImageVideoFetcher中的loadData方法:

public ImageVideoWrapper loadData(Priority priority) throws Exception {
    InputStream is = null;
    if (streamFetcher != null) {
        try {
            is = streamFetcher.loadData(priority);
        } catch (Exception e) {
            if (fileDescriptorFetcher == null) {
                throw e;
            }
        }
    }
    ParcelFileDescriptor fileDescriptor = null;
    if (fileDescriptorFetcher != null) {
        try {
            fileDescriptor = fileDescriptorFetcher.loadData(priority);
        } catch (Exception e) {
            if (is == null) {
                throw e;
            }
        }
    }
    return new ImageVideoWrapper(is, fileDescriptor);
}

先看第5行代码,这里调用了streamFetcher的loadData方法,那streamFetcher是个什么东东呢?它就是在前面调用ImageVideoModelLoader的getResourceFetcher方法时,传入的HttpUrlFetcher,我们先看看HttpUrlFetcher的loadData方法,这里应该要下载图片了

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

这里直接调用了loadDataWithRedirects方法并返回,下面看看该方法

private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map headers)
        throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
        throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
        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 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());
    }
}

第28行代码,调用了connectionFactory的build方法,用于构建网络通信的Connection,而connectonFactory是个HttpUrlConnectionFactory接口的对象,HttpUrlConnectionFactory的默认实现类为DefaultHttpUrlConnectionFactory,如下:

interface HttpUrlConnectionFactory {
    HttpURLConnection build(URL url) throws IOException;
}

private static class DefaultHttpUrlConnectionFactory implements HttpUrlConnectionFactory {
    @Override
    public HttpURLConnection build(URL url) throws IOException {
        return (HttpURLConnection) url.openConnection();
    }
}

这里直接返回了一个HttpURLConnection对象,原来Glide中下载图片是使用的HttpURLConnection
再回到loadDataWithRedirects方法的第20行代码,一般下载图片成功是返回200状态码,所以会调用getStreamForSuccessfulRequest方法,我们看看这个方法:

private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
        throws IOException {
    if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
        int contentLength = urlConnection.getContentLength();
        stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
    } else {
        stream = urlConnection.getInputStream();
    }
    return stream;
}

可以看到,这个方法就是通过HttpURLConnection的getInputStream方法,得到InputStream并返回。
然后逐级返回,来到ImageVideoFetcher的loadData方法的最后一行代码,这里就是通过HttpURLConnection返回的InputStream对象,包装成一个ImageVideoWrapper对象,并返回
然后返回到DecodeJob的decodeStream方法,再调用了ImageVideoFetcher的loadData方法得到ImageVideoWrapper对象以后,调用了decodeFromSourceData方法,并把ImageVideoWrapper传入进去,进行图片解码,我们来看看decodeFromSourceData方法:

private Resource decodeFromSourceData(A data) throws IOException {
    final Resource decoded;
    if (diskCacheStrategy.cacheSource()) {
        decoded = cacheAndDecodeSourceData(data);
    } else {
        long startTime = LogTime.getLogTime();
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
    }
    return decoded;
}

这里的主要逻辑是第7行代码,先调用了loadProvider的getSourceDecoder方法,loadProvider就是在Engine的load方法中构建DecodeJob时传进来的FixedLoadProvider对象,而它的getSourceDecoder方法如下:

public ResourceDecoder getSourceDecoder() {
    return dataLoadProvider.getSourceDecoder();
}

可以看到这里就是调用了dataLoadProvider的getSourceDecoder方法,而dataLoadProvider是在DrawableTypeRequest的buildProvider方法中构建FixLoadProvider时传入的ImageVideoGifDrawableLoadProvider对象,我们看看ImageVideoGifDrawableLoadProvider的getSourceEncoder方法:

@Override
public Encoder getSourceEncoder() {
    return sourceEncoder;
}

public ImageVideoGifDrawableLoadProvider(DataLoadProvider bitmapProvider,
        DataLoadProvider gifProvider, BitmapPool bitmapPool) {

    final GifBitmapWrapperResourceDecoder decoder = new GifBitmapWrapperResourceDecoder(
            bitmapProvider.getSourceDecoder(),
            gifProvider.getSourceDecoder(),
            bitmapPool
    );
    cacheDecoder = new FileToStreamDecoder(new GifBitmapWrapperStreamResourceDecoder(decoder));
    sourceDecoder = decoder;
    encoder = new GifBitmapWrapperResourceEncoder(bitmapProvider.getEncoder(), gifProvider.getEncoder());

    //TODO: what about the gif provider?
    sourceEncoder = bitmapProvider.getSourceEncoder();
}

可知,得到的是一个GifBitmapWrapperResourceDecoder对象,所以decodeFromSourceData方法中loadProvider.getSourceDecoder().decode()其实就是调用GifBitmapWrapperResourceDecoder类中的decode方法,如下:

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

第6行代码,直接调用了decode的重载方法,得到解析出来的图片资源,然后在最后一行代码包装成GifBitmapWrapperResource对象,并返回。
我们先看decode的重载方法:

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

这里的source.getStream其实就是之前用HttpURLConnection得到的图片InputStream,所以不为空,则调用decodeStream对输入流进行解码,再看decodeStream的源码:

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

这里先对流进行了解析,判断图片格式是否是Gif格式,如果是,则执行第10行代码,解析Gif图片;如果不是,则执行第17行代码,解析静态图片。我们这里是静态图片,所以会调用decodeBitmapWrapper方法,我们看看源码:

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

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

    return result;
}

这里调用bitmapDecoder的decode方法,那bitmapDecoder方法是个什么对象呢?这个就说来话长了还记得,GifBitmapWrapperResourceDecoder中有这么一段代码:

public ImageVideoGifDrawableLoadProvider(DataLoadProvider bitmapProvider,
        DataLoadProviderifDrawable> gifProvider, BitmapPool bitmapPool) {

    final GifBitmapWrapperResourceDecoder decoder = new GifBitmapWrapperResourceDecoder(
            bitmapProvider.getSourceDecoder(),
            gifProvider.getSourceDecoder(),
            bitmapPool
    );
    cacheDecoder = new FileToStreamDecoderifBitmapWrapper>(new GifBitmapWrapperStreamResourceDecoder(decoder));
    sourceDecoder = decoder;
    encoder = new GifBitmapWrapperResourceEncoder(bitmapProvider.getEncoder(), gifProvider.getEncoder());

    //TODO: what about the gif provider?
    sourceEncoder = bitmapProvider.getSourceEncoder();
}

其实bitmapDecoder就是上处第5行代码bitmapProvider.getSourceDecoder的返回值,而bitmapProvider又是什么呢?这就要看到找到创建ImageVideoGifDrawableLoadProvid的地方了,这个代码在Glide的构造方法里

Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
    dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
            new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
}

所以bitmapProvider就是一个ImageVideoDataLoadProvider对象,所以bitmapDecoder就是ImageVideoDataLoadProvider的getSourceDecoder方法的返回值,我们看看该方法:

public ImageVideoDataLoadProvider(DataLoadProvider streamBitmapProvider,
        DataLoadProvider fileDescriptorBitmapProvider) {
    encoder = streamBitmapProvider.getEncoder();
    sourceEncoder = new ImageVideoWrapperEncoder(streamBitmapProvider.getSourceEncoder(),
            fileDescriptorBitmapProvider.getSourceEncoder());
    cacheDecoder = streamBitmapProvider.getCacheDecoder();
    sourceDecoder = new ImageVideoBitmapDecoder(streamBitmapProvider.getSourceDecoder(),
            fileDescriptorBitmapProvider.getSourceDecoder());
}

@Override
public ResourceDecoder getSourceDecoder() {
    return sourceDecoder;
}

可知,bitmapDecoder其实就是一个ImageVideoBitmapDecoder对象,回到GifBitmapWrapperResourceDecoder的decodeBitmapWrapper方法,继续主流程,那这时候就是调用的ImageVideoBitmapDecoder的decode方法,代码如下:

public Resource decode(ImageVideoWrapper source, int width, int height) throws IOException {
    Resource result = null;
    InputStream is = source.getStream();
    if (is != null) {
        try {
            result = streamDecoder.decode(is, width, height);
        } catch (IOException e) {

        }
    }

    if (result == null) {
        ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
        if (fileDescriptor != null) {
            result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
        }
    }
    return result;
}

关键代码就是第6行代码,调用了streamDecoder的decode方法,那streamDecoder是个什么对象呢?其实和ImageVideoBitmapDecoder逻辑差不多,也是在Glide的构造方法里有这么一段:

Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {

    StreamBitmapDataLoadProvider streamBitmapLoadProvider =
            new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat); 

ImageVideoDataLoadProvider imageVideoDataLoadProvider =
        new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);


dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
        new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
}

就是这样逐级封装,我们看看StreamBitmapDataLoadProvider的构造方法:

public StreamBitmapDataLoadProvider(BitmapPool bitmapPool, DecodeFormat decodeFormat) {
    sourceEncoder = new StreamEncoder();
    decoder = new StreamBitmapDecoder(bitmapPool, decodeFormat);
    encoder = new BitmapEncoder();
    cacheDecoder = new FileToStreamDecoder(decoder);
}

所以streamDecoder其实就是一个StreamBitmapDecoder对象,继续回到ImageVideoBitmapDecoder的decode方法中,继续主流程,相当于调用了StreamBitmapDecoder中的decode方法,代码如下:

@Override
public Resource decode(InputStream source, int width, int height) {
    Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
    return BitmapResource.obtain(bitmap, bitmapPool);
}

第3行代码,是调用DownSampler中的decode方法,从InputStream解析处Bitmap
第4行代码,是调用BitmapResource的obtain方法,把解析出的Bitmap封装成BitmapResource对象中,并返回
我们先看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();

    // Use to fix the mark limit to avoid allocating buffers that fit entire images.
    RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
            is, bytesForStream);
    // Use to retrieve exceptions thrown while reading.
    // TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a way to determine
    // if a Bitmap is partially decoded, consider removing.
    ExceptionCatchingInputStream exceptionStream =
            ExceptionCatchingInputStream.obtain(bufferedStream);
    // Use to read data.
    // Ensures that we can always reset after reading an image header so that we can still attempt to decode the
    // full image even when the header decode fails and/or overflows our read buffer. See #283.
    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);
    }
}

这里的核心代码就是第47行代码,调用里downsampleWithSize方法,并得到Bitmap,终于要到从InputStream解除Bitmap的地方里,是不是使用的我们常用的BitmapFactory.decodeStream的方式去解析的呢?继续往下看:

private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream  bufferedStream,
        BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,
        DecodeFormat decodeFormat) {
    // Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
    Bitmap.Config config = getConfig(is, decodeFormat);
    options.inSampleSize = sampleSize;
    options.inPreferredConfig = config;
    if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {
        int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);
        int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);
        // BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
        setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));
    }
    return decodeStream(is, bufferedStream, options);
}

这个方法里有对options的设置,核心代码就是第14行代码,调用了decodeStream方法,解析出Bitmap并返回,我们继续往下跟踪:

private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
        BitmapFactory.Options options) {
     if (options.inJustDecodeBounds) {
         // This is large, but jpeg headers are not size bounded so we need something large enough to minimize
         // the possibility of not being able to fit enough of the header in the buffer to get the image size so
         // that we don't fail to load images. The BufferedInputStream will create a new buffer of 2x the
         // original size each time we use up the buffer space without passing the mark so this is a maximum
         // bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb.
         is.mark(MARK_POSITION);
     } else {
         // Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid
         // unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our
         // current buffer size here. See issue #225.
         bufferedStream.fixMarkLimit();
     }

    final Bitmap result = BitmapFactory.decodeStream(is, null, options);

    try {
        if (options.inJustDecodeBounds) {
            is.reset();
        }
    } catch (IOException e) {

    }
    return result;
}

真是千呼万唤始出来,第17行代码,就是使用的BitmapFactory的decodeStream方法,从InputStream解析出图片,当然,Glide已经对options参数已经进行过处理,这里我们就不展开了。到这里,Glide就完成了图片的下载和解析。
我们继续逐级返回到StreamBitmapDecode类中的decode方法,这里会返回BitmapResource对象,里面封装了Bitmap。
再返回到GifBitmapWrapperResourceDecoder类中的decodeBitmapWrapper方法,这里会创建一个GifBitmapWrapper对象,里面封装了BitmapResource,并返回
再返回到GifBitmapWrapperResourceDecoder类中的decode方法,这里会创建一个GifBitmapWarpperResource对象,里面封装了GifBitmapWrapper,并返回
我们再回到DecodeJob.decodeFromSource方法,再来看一遍代码:

public Resource decodeFromSource() throws Exception {
    Resource decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}

由之前的分析可得,decodeSource返回了一个GifBitmapWarpperResource对象,并把该对象传入到transfromEncodeAndTranscode方法中进行转换,我们继续沿着转换的逻辑往下走:

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

关键代码就是上述第11行代码,调用了transcode方法,把Resource转变成了Resource,由之前的分析可得,Resource就是GifBitmapWarpperResource,那Rsource是什么呢?继续往下看:

private Resource transcode(Resource transformed) {
    if (transformed == null) {
        return null;
    }
    return transcoder.transcode(transformed);
}

这里直接调用了transcoder的transcode方法,那transcoder是什么对象呢?它就是中Engine的load方法中构建DecodeJob对象时,传入的GifBitmapWrapperDrawableTranscoder对象,那我们来看看GifBitmapWrapperDrawableTranscoder的transcode方法:

public Resource transcode(Resource toTranscode) {
    GifBitmapWrapper gifBitmap = toTranscode.get();
    Resource bitmapResource = gifBitmap.getBitmapResource();

    final Resource result;
    if (bitmapResource != null) {
        result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
    } else {
        result = gifBitmap.getGifResource();
    }
    // This is unchecked but always safe, anything that extends a Drawable can be safely cast to a Drawable.
    return (Resource) result;
}

第3行代码,就是从GifBitmapWarpperResource中取出GifBitmapWarpperResource
第7行代码,调用了bitmapDrawableResourceTranscoder的transcode方法,bitmapDrawableResourceTranscoder是个什么对象呢?这个也可以从Glide的构造方法里找到,这里就不展开了,它其实就是一个GlideBitmapDrawableTranscoder对象,我们来看它的transcode方法:

@Override
public Resource transcode(Resource toTranscode) {
    GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
    return new GlideBitmapDrawableResource(drawable, bitmapPool);
}

这个方法就是从GifBitmapWarpperResource中取出Bitmap,然后构建出GlideBitmapDrawableResource对象,这里其实就是为了图片的统一显示,把封装Bitmap的GifBitmapWarpperResource对象,转换成封装GlideBitmapDrawable的GlideBitmapDrawableResource对象。
这里就逐级返回GlideBitmapDrawableResource,一直到EngineRunnable的run方法中,我们再来看看run方法:

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

    Exception exception = null;
    Resource> resource = null;
    try {
        resource = decode();
    } catch (Exception e) {
        exception = e;
    }

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

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

我们之前流程分析的都是第9行代码的decode,即完成了图片的下载、解析、转换,并返回了GlideBitmapDrawableResource对象,这时候就来到最后的流程,图片展示。
我们先看第24行代码,即图片下载成功,会调用onLoadComplete方法,源码如下:

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

这里直接调用了manager的onRsourceReady方法,manager是个什么对象呢?其实就是在Engine.load方法中创建EngineRunnable时传入的EngineJob对象,我们看看EngineJob的onResourceReady

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

这个方法还是在子线程当中执行的,所以为了给ImageView设置图片,使用Handler发消息,注意的一点,这里会把this即EnginJob当作msg.obj发送出去,我们来看看MAIN_THREAD_HANDLER的定义

class EngineJob implements EngineRunnable.EngineRunnableManager {
    private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());

它其实是EnginJob中的一个static属性,注意的一点就是,在创建Handler时,传入了主线程的Looper,这样就保证了通过MAIN_THREAD_HANDLER这个Handler发送的消息,永远是在主线程中处理的。
我们来看看MainThreadCallback的handlerMessage方法,在这里会响应MSG_COPLETE的消息:

private static class MainThreadCallback implements Handler.Callback {
    @Override
    public boolean handleMessage(Message message) {
        if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
            EngineJob job = (EngineJob) message.obj;
            if (MSG_COMPLETE == message.what) {
                job.handleResultOnMainThread();
            } else {
                job.handleExceptionOnMainThread();
            }
            return true;
        }
        return false;
    }
}

之前提到的,在onResourceReady使用Handler发送消息时,把EnginJob也一起发送过来了,所以在上述第5行代码,可以通过message.obj得到EngineJob,然后执行到第7行代码,调用了EngineJob的handleResoultOnMainThread方法,我们来看看这个方法:

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

这里关键代码是上述第19行代码,调用了cb的onResourceReady方法,cb是从ResourceCallback中循环出来的,那cb是什么呢?还记得前面分析是调用过cb的onSizeReady方法,没错cb就是GenericRequest对象,它实现了ResourceCallback接口。它是在Engine.load方法中调用EngineJob.addCallback把GenericRequest对象,加入到EngineJob的回调集合中的。
所以这里调用的是GenericRequest中的onResourceReady方法,代码如下:

public void onResourceReady(Resource resource) {
    if (resource == null) {
        onException(new Exception("Expected to receive a Resource 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);
}

关键的代码就是上述最后一行代码,调用了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 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方法,target是什么呢?它其实是调用GenericRequest.obtaion来构造GenericeRequest对象时,传入的GlideDrawableImageViewTarget对象,所以我们继续看GlideDrawableImageViewTarget的onResourceReady方法:

public void onResourceReady(GlideDrawable resource, GlideAnimationsuper GlideDrawable> animation) {
    if (!resource.isAnimated()) {
        //TODO: Try to generalize this to other sizes/shapes.
        // This is a dirty hack that tries to make loading square thumbnails and then square full images less costly
        // by forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions.
        // If a drawable is replaced in an ImageView by another drawable with different intrinsic dimensions,
        // the ImageView requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers
        // lots of these calls and causes significant amounts of jank.
        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();
}

这里其实就是调用了父类的ImageViewTarget的onResourceReady方法,代码如下:

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

这里调用了子类GlideDrawableImageViewTarget的setResource方法:

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

终于,网络图片就显示到了ImageView上
到这里,Glide.with().load().into()正常加载网络图片的流程就分析完了
而EngineRunnable的run方法中,如果decode方法返回的图片资源为null,则会调用onLoadFailed方法,这个也是通过Handler发消息,然后在主线程中设置加载失败的图片资源,流程和onLoadComplete完全一样,就不展开分析了。

可知Glide加载图片的主要流程就是:

  1. with:创建RequestManager,并根据传入参数,初始化好对应的生命周期
  2. load:用于初始化好图片下载、图片解析、图片转换的各个对象,用于后续流程
  3. into:在线程池中去执行EngineRunnale的run方法,用HttpURLConnection下载图片、用BitmapFactory.decodeStream完成解码、然后把Bitmap转换成可统一展示的GlideBitmapDrawable、最后通过Handler发消息,在主线程中给ImageView设置图片

再回到开始的问题:
1. Glide图片是用什么来下载的?HttpClient还是HttpURLConnection?亦或OKHttp?
答:Glide的图片是使用HttpURLConnectioin来下载的
2. Glide图片是通过怎么解码的?是我们通常使用的BitmapFactory.decodeXXX方法么?
答:Glide图片解码就是使用BitmapFactory.decodeStream方法解码的
3. Glide下载好图片以后,是怎么加载到ImageView上的?
答:Glide下载好图片以后,是使用Handler发消息,把图片设置到ImageView上
4. Glide怎么实现缓存的?是LruCache和DiskLruCache么?
5. Glide的线程是怎么管理的?几个核心线程?几个最大线程?有最大任务数的限制么?
6. Glide是怎么支持Gif图的?是通过Movie对象么?

至于4、5、6的问题,等下篇博客来一起探讨吧!强烈欢迎留言,一起讨论Glide的问题。

你可能感兴趣的:(Android)