Android 图片框架原理——Glide源码分析

Android 图片框架原理——Glide源码分析_第1张图片

目录

前言

一、With()

二、load()

三、into()

1、 buildImageViewTarget()

2、关注1 :buildRequest 构建

3、关注2:runRequest 执行

总结

补充,Glide缓存机制:


前言

作用Android开发者,相信大家都知道Glide这款优秀的Android图片加载库。它支持拉取、解码、展示,视频快照、图片和GIF动画。提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 使用简明的流式(链式)语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求,因此搞懂这条链式调用的代码都做了什么准备工作,Glide图片加载的大概框架也就明白了许多。

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

 配置要求

Glide v4最低支持Android Ice Cream Sandwich (API level 14).

优势概述

Glide比较吸引人的主要还是与Activity生命周期进行绑定、加载gif图片、可以配置相应的网络请求框架。

 一、With()

概述:With() 通过RequestManagerRetriever的单例,静态get方法拿到其对象实例,然后通过成员函数get方法,通过getApplicationManager(Context)方法最终拿到RequestManager实例。

//1 Context
public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        /**
          *  retriever  n. (训练成能寻回猎物的)寻回犬;取回的人,挽救者
          */
        return retriever.get(context);
    }
//2 Activity
public static RequestManager with(Activity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
//3 FragmentActivity
public static RequestManager with(FragmentActivity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
//4 android.app.Fragment
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static RequestManager with(android.app.Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }
//5 Fragment
 public static RequestManager with(Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }

上面共有五种with方法重载。都是调用RequestManagerRetriever类的静态get方法获取到实例对象,属于是一个饿汉式单例模式。然后,再将参数传入retriever对象的get方法中,拿到RequestManager对象。源码如下:

RequestManagerRetriever.class

public class RequestManagerRetriever implements Handler.Callback {
   //...
    final Map pendingSupportRequestManagerFragments =
            new HashMap();
   //...
    public static RequestManagerRetriever get() {
        return INSTANCE;
    }
    RequestManagerRetriever() {
        handler = new Handler(Looper.getMainLooper(), this /* Callback */);
    }
    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(Context context) {
        if (context == null) {
            //..
        } 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);
    }
 
    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) {
           //..
        }
        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)
    private static void assertNotDestroyed(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) { //..
        }
    }
 
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public RequestManager get(android.app.Fragment fragment) {
        if (fragment.getActivity() == null) { //..
        }
        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;
    }
 
    @Override
    public boolean handleMessage(Message message) {
        boolean handled = true;
        Object removed = null;
        Object key = null;
        switch (message.what) {
            case ID_REMOVE_FRAGMENT_MANAGER:
                android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
                key = fm;
                removed = pendingRequestManagerFragments.remove(fm);
                break;
            case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
                FragmentManager supportFm = (FragmentManager) message.obj;
                key = supportFm;
                removed = pendingSupportRequestManagerFragments.remove(supportFm);
                break;
            default:
                handled = false;
        }
        if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
           //..
        }
        return handled;
    }
}

上面的静态get()挺多,其实只分为两种,即application类型与application类型的参数。如果是application类型参数,会调用getApplicationManager(Context),最后返回一个RequestManager对象实例;如果是非application类型参数,最后都会向当前的Activity添加一个隐藏的Fragmen。

Glide需要拿到加载的生命周期,当我们在Activity加载一张图片,图片还没有加载,Activity就被销毁了,那图片就不用加载。把Glide放到Fragment中,当Activity销毁,Fragment是可以监听到的,这样也可以实现需求。

二、load()

概述:load()方法通过fromString()调用loadGeneric(),返回asBitmap()相关的DrawableTypeRequest对象,调用DrawableRequestBuilder父类中load方法,给父类成员变量赋值后,在RequestManager类中将DrawableRequestBuilder父类对象强转成子类DrawableTypeRequest。load方法最终拿到了DrawableTypeRequest对象。

我们都知道Glide可以加载本地图片、res目录下图片、网络图片等等。所以load()方法也是有很多方法重载的。这里只看网络加载图片URL字符串的load()方法,查看源码如下。

RequestManager.class    

public class RequestManager extends DrawableRequestBuilder implements LifecycleListener {
    //...
    public DrawableTypeRequest load(String string) {
        return (DrawableTypeRequest) fromString().load(string);
    }
    public DrawableTypeRequest fromString() {
        return loadGeneric(String.class);
    }
    private  DrawableTypeRequest loadGeneric(Class modelClass) {
    //streamModelLoader
        ModelLoader streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
    //fileDescriptorModelLoader
        ModelLoader 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");
        }
    //  DrawableTypeRequest()
      return optionsApplier.apply(
                new DrawableTypeRequest(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }
}

可见,load()最终调用了loadGeneric()。其中,Glide.buildStreamModelLoader、buildFileDescriptorModelLoader静态方法来拿到相应的ModelLoader对象。ModelLoader对象用于加载图片,传入不同的参数能拿到对应的ModelLoader对象。最终传入到 DrawableTypeRequest构造方法中如下。

public class DrawableTypeRequest extends DrawableRequestBuilder implements DownloadOptions {
    private final ModelLoader streamModelLoader;
    private final ModelLoader fileDescriptorModelLoader;
    private final RequestManager.OptionsApplier optionsApplier;
    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);
    }
    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;
    }
    public BitmapTypeRequest asBitmap() {
        return optionsApplier.apply(new BitmapTypeRequest(this, streamModelLoader,
                fileDescriptorModelLoader, optionsApplier));
    }
 
    public GifTypeRequest asGif() {
        return optionsApplier.apply(new GifTypeRequest(this, streamModelLoader, optionsApplier));
    }
}

这个类中重点在于asGif()、asBitmap()这两个方法,加载静态图片和动态图片的不同方式,分别创建了BitmapTypeRequest和GIFTypeRequest对象,如果不指定的话默认是创建静态图片的对象BitmapTypeRequest。

三、into()

概述:①初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),②使用最原始的HTTPConnect网络连接,读取文件流,③根据文件判断是GIF动图还是Bitmap静态图片,④通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件。

Into()是RequestManager的父类是DrawableRequestBuilder中的方法,源码如下。

public class DrawableRequestBuilder
        extends GenericRequestBuilder
        implements BitmapOptions, DrawableOptions {
    DrawableRequestBuilder(Context context, Class modelClass,
            LoadProvider loadProvider, Glide glide,
            RequestTracker requestTracker, Lifecycle lifecycle) {
        super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
        crossFade();
    }
    public DrawableRequestBuilder thumbnail(
            DrawableRequestBuilder thumbnailRequest) {
        super.thumbnail(thumbnailRequest);
        return this;}
    @Override
    public DrawableRequestBuilder thumbnail(
            GenericRequestBuilder thumbnailRequest) {
        super.thumbnail(thumbnailRequest);
        return this;}
    @Override
    public DrawableRequestBuilder thumbnail(float sizeMultiplier) {
        super.thumbnail(sizeMultiplier);
        return this; }
    @Override
    public DrawableRequestBuilder sizeMultiplier(float sizeMultiplier) {
        super.sizeMultiplier(sizeMultiplier);
        return this; }
    @Override
    public DrawableRequestBuilder decoder(ResourceDecoder decoder) {
        super.decoder(decoder);
        return this;}
    @Override
    public DrawableRequestBuilder cacheDecoder(ResourceDecoder cacheDecoder) {
        super.cacheDecoder(cacheDecoder);
        return this;}
    @Override
    public DrawableRequestBuilder encoder(ResourceEncoder encoder) {
        super.encoder(encoder);
        return this;}
    @Override
    public DrawableRequestBuilder priority(Priority priority) {
        super.priority(priority);
        return this;}
    public DrawableRequestBuilder transform(BitmapTransformation... transformations) {
        return bitmapTransform(transformations);}

    public DrawableRequestBuilder centerCrop() {
        return transform(glide.getDrawableCenterCrop());
    }
    public DrawableRequestBuilder fitCenter() {
        return transform(glide.getDrawableFitCenter());
    }
    public DrawableRequestBuilder bitmapTransform(Transformation... bitmapTransformations) {
        GifBitmapWrapperTransformation[] transformations =
                new GifBitmapWrapperTransformation[bitmapTransformations.length];
        for (int i = 0; i < bitmapTransformations.length; i++) {
            transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
        }
        return transform(transformations);}
    @Override
    public DrawableRequestBuilder transform(Transformation... transformation) {
        super.transform(transformation);
        return this;}
    @Override
    public DrawableRequestBuilder transcoder(
            ResourceTranscoder transcoder) {
        super.transcoder(transcoder);
        return this;}
    public final DrawableRequestBuilder crossFade() {
        super.animate(new DrawableCrossFadeFactory());
        return this;
    }
    public DrawableRequestBuilder crossFade(int duration) {
        super.animate(new DrawableCrossFadeFactory(duration));
        return this;
    }
    public DrawableRequestBuilder crossFade(int animationId, int duration) {
        super.animate(new DrawableCrossFadeFactory(context, animationId,
                duration));
        return this;}
    @Override
    public DrawableRequestBuilder dontAnimate() {
        super.dontAnimate();
        return this; }
    @Override
    public DrawableRequestBuilder animate(ViewPropertyAnimation.Animator animator) {
        super.animate(animator);
        return this; }
    @Override
    public DrawableRequestBuilder animate(int animationId) {
        super.animate(animationId);
        return this;}
    @Override
    public DrawableRequestBuilder placeholder(int resourceId) {
        super.placeholder(resourceId);
        return this;}
    @Override
    public DrawableRequestBuilder placeholder(Drawable drawable) {
        super.placeholder(drawable);
        return this;}
    @Override
    public DrawableRequestBuilder fallback(Drawable drawable) {
        super.fallback(drawable);
        return this;}
    @Override
    public DrawableRequestBuilder fallback(int resourceId) {
        super.fallback(resourceId);
        return this;
    }
    @Override
    public DrawableRequestBuilder error(int resourceId) {
        super.error(resourceId);
        return this;
    }
    @Override
    public DrawableRequestBuilder error(Drawable drawable) {
        super.error(drawable);
        return this;
    }
    @Override
    public DrawableRequestBuilder listener(
            RequestListener requestListener) {
        super.listener(requestListener);
        return this;
    }
    @Override
    public DrawableRequestBuilder diskCacheStrategy(DiskCacheStrategy strategy)             {
        super.diskCacheStrategy(strategy);
        return this;}
    @Override
    public DrawableRequestBuilder skipMemoryCache(boolean skip) {
        super.skipMemoryCache(skip);
        return this; }
    @Override
    public DrawableRequestBuilder override(int width, int height) {
        super.override(width, height);
        return this;}
    @Override
    public DrawableRequestBuilder sourceEncoder(Encoder sourceEncoder) {
        super.sourceEncoder(sourceEncoder);
        return this;}
    @Override
    public DrawableRequestBuilder dontTransform() {
        super.dontTransform();
        return this;}
    @Override
    public DrawableRequestBuilder signature(Key signature) {
        super.signature(signature);
        return this;}
    @Override
    public DrawableRequestBuilder load(ModelType model) {
        super.load(model);
        return this;}
    @Override
    public DrawableRequestBuilder clone() {
        return (DrawableRequestBuilder) super.clone();}
    @Override
    public Target into(ImageView view) {
        return super.into(view);}
    @Override
    void applyFitCenter() {
        fitCenter(); }
    @Override
    void applyCenterCrop() {
        centerCrop();
    }
}

 可以看到 DrawableRequestBuilder类的方法很多,都是直接传参数,没有什么逻辑控制,通过传参,改变了当前的成员变量的值,这也是建造者设计模式。 DrawableRequestBuilder类中的into()方法没有逻辑而是调用了一句super.into()代码,显然into()的业务逻辑是在它的父类GenericRequestBuilder中,点进去看一下源码:

public Target into(ImageView view) {
    Util.assertMainThread();//主线程
    if (view == null) {}
    if (!isTransformationSet && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                applyCenterCrop();
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                applyFitCenter();
                break;
            default:
                // Do nothing.
        }
    }
    return into(glide.buildImageViewTarget(view, transcodeClass));
}

1、 buildImageViewTarget()

 Util.assertMainThread()判断当前线程是不是主线程,主要就是用Looper.myLooper()与Looper.getMainLooper()做对比来确定的。into()方法参数中调用buildImageViewTarget(),这个方法会构建出一个Target对象,用来最终展示图片。

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

public class ImageViewTargetFactory {
    @SuppressWarnings("unchecked")
    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)) {
           //(DrawableImageViewTarget基本上用不到,不关注它。)
            return (Target) new DrawableImageViewTarget(view);
        } else {
            throw new IllegalArgumentException("Unhandled class: " + clazz
                    + ", try .as*(Class).transcode(ResourceTranscoder)");
        } }
} 

ImageViewTargetFactory工厂类根据不同clazz参数来构建Target对象,clazz参数有两种情况:

1、使用Glide加载图片的时候调用了asBitmap()方法,这里就会构建BitmapImageViewTarget对象。

2、默认都是生成了GlideDrawableImageViewTarget对象。

GenericRequestBuilder.into()方法将GlideDrawableImageViewTarget对象传给了它内部的into()方法:

public > Y into(Y target) {
    //..
    Request request = buildRequest(target);//关注1
    target.setRequest(request);
    lifecycle.addListener(target);
    requestTracker.runRequest(request);//关注2
    return target;
}

2、关注1 :buildRequest 构建

buildRequest(target)是用来发出加载图片请求的,它是Glide中非常关键的一个组件,我们先来看buildRequest()方法是如何构建Request对象的: 

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) { }
            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);
            isThumbnailBuilt = true;
            Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
            isThumbnailBuilt = false;
            coordinator.setRequests(fullRequest, thumbRequest);
            return coordinator;
        } else if (thumbSizeMultiplier != null) {
            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 {
            //注释1
            return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
        }
    }

这里主要是在处理缩略图的。最后“注释1”处调用了obtainRequest()方法来获取一个Request对象,而obtainRequest()方法中又去调用了GenericRequest的obtain()方法。代码如下:

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

注意obtain()方法需要传入非常多的参数,而其中很多的参数我们都是比较熟悉的,像什么placeholderId、errorPlaceholder、diskCacheStrategy等等。因此,我们就有理由猜测,刚才在load()方法中调用的所有API,其实都是在这里组装到Request对象当中的。那么我们进入到这个GenericRequest.obtain()方法看看。

public final class GenericRequest implements Request, SizeReadyCallback,
        ResourceCallback {
    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,
            RequestListener 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;
    }
 ...
}

obtain()方法实际上获得的就是一个GenericRequest对象,代码中创建了GenericRequest对象,并放到return中。GenericRequest的init(),里面主要就是一些赋值的代码,将传入的这些参数赋值到GenericRequest的成员变量当中。

到这里基本解决了构建Request对象的问题,接下来我们看一下这个Request对象又是怎么执行的。回到前面说的into()方法最后调用了requestTracker.runRequest()方法来去执行这个Request。如下所示:

3、关注2:runRequest 执行

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

这里先判断Glide当前是不是Paused(暂停)状态,如果不是就调用Request.begin()方法去执行,否则就先将Request对象添加到待执行队列里面,等暂停状态解除后再执行。我们重点来看这个begin()方法。由于当前的Request对象是一个GenericRequest,因此这里是GenericRequest.begin(),如下所示:

public abstract class ImageViewTarget extends ViewTarget implements GlideAnimation.ViewAdapter {
    ...
    @Override
    public void onLoadStarted(Drawable placeholder) {//显示占位图
        view.setImageDrawable(placeholder);
    }
    @Override
    public void onLoadFailed(Exception e, Drawable errorDrawable) {//显示错误图
        view.setImageDrawable(errorDrawable);
    }
    ...
}
@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());
    }
}

model是load()方法中传入的图片URL地址。如果model等于null,会调用onException()方法。如果你跟到onException()方法里面最终会调用到一个setErrorPlaceholder(),设置错误占位图。

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

当出现了异常,没办法展示正常的图片了,将error占位图显示到ImageView上。

再说回begin()方法,它最后调用了target.onLoadStarted()方法,并传入了一个loading占位图,在图片请求开始之前,会先使用这张占位图代替最终的图片显示。这就是Glide的placeholder()和 error()这两个占位图API底层的实现原理。 

上面begin()方法中还调用了onSizeReady(overrideWidth, overrideHeight);和 target.getSize(this);。这里要分两种情况,一种是手动为图片指定了宽高,一种是没有指定。如果指定了的话,就会执行onSizeReady()方法。如果没指定的话,就会执行target.getSize()方法。

这个target.getSize()方法的内部会根据ImageView控件的layout_width和layout_height值做一系列的计算,来算出图片对应的宽高,总之在计算完之后,最终还是会调用onSizeReady()方法。如下。

    @Override
    public void onSizeReady(int width, int height) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {}
        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) {
            return;
        }
        ResourceTranscoder transcoder = loadProvider.getTranscoder();
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
    }

这里分别调用了loadProvider的getModelLoader()方法和getTranscoder()方法,他们会得到ImageVideoModelLoader和GifBitmapWrapperDrawableTranscoder。最后调用engine.load(),源码如下:

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
    public  LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
            DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder 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);
            return null;
        }
        EngineResource active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            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 decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation,
                transcoder, diskCacheProvider, diskCacheStrategy, priority);
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        engineJob.start(runnable);
        return new LoadStatus(cb, engineJob);
    }
}

 最后调用了 engineJob.start(runnable); 跟踪代码看看这个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);
    }
}

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

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

这里主要调用了一个decode()方法,并且这个方法返回了一个Resource对象。decode()方法中又分了两种情况,从缓存当中去decode图片的话就会执行decodeFromCache(),否则的话就执行decodeFromSource(),之后又调用了DecodeJob的decodeFromSource()方法。看一下DecodeJob源码:

class DecodeJob {
    public Resource decodeFromSource() throws Exception {
        Resource decoded = decodeSource();
        return transformEncodeAndTranscode(decoded);
    }
    private Resource decodeSource() throws Exception {
        Resource decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            final A data = fetcher.loadData(priority);
            if (isCancelled) {
                return null;
            }
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }
}

它的工作分为两部,第一步是调用decodeSource()方法来获得一个Resource对象,第二步是调用transformEncodeAndTranscode()方法来处理这个Resource对象。

那么我们先来看第一步,decodeSource()方法中的逻辑也并不复杂,首先调用了fetcher.loadData()方法。那么这个fetcher是什么呢?其实就是刚才在onSizeReady()方法中得到的ImageVideoFetcher对象,这里调用它的loadData()方法,代码如下所示:

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

在ImageVideoFetcher的loadData()方调用了streamFetcher.loadData()方法。那么这个streamFetcher是什么呢?自然就是刚才在组装ImageVideoFetcher对象时传进来的HttpUrlFetcher了。因此这里又会去调用HttpUrlFetcher的loadData()方法。

public class HttpUrlFetcher implements DataFetcher {
    @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 headers)
            throws IOException {
        if (redirects >= MAXIMUM_REDIRECTS) {
            throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
        } else {
          //..
        }
        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);
        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 {
           //..
        }
    }
    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;
    }
}

可以看到,loadData()方法只是返回了一个InputStream,服务器返回的数据连读都还没开始读呢。所以我们还是要静下心来继续分析,回到刚才ImageVideoFetcher的loadData()方法中,在这个方法的最后一行,创建了一个ImageVideoWrapper对象,并把刚才得到的InputStream作为参数传了进去。然后我们回到再上一层,也就是DecodeJob的decodeSource()方法当中,在得到了这个ImageVideoWrapper对象之后,紧接着又将这个对象传入到了decodeFromSourceData()当中,来去解码这个对象。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);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded from source", startTime);
        }
    }
    return decoded;
}

这里调用了loadProvider.getSourceDecoder().decode()方法来进行解码。loadProvider就是刚才在onSizeReady()方法中得到的FixedLoadProvider,而getSourceDecoder()得到的则是一个GifBitmapWrapperResourceDecoder对象,也就是要调用这个对象的decode()方法来对图片进行解码。那么我们来看下GifBitmapWrapperResourceDecoder的代码:

public class GifBitmapWrapperResourceDecoder implements ResourceDecoder {
    @SuppressWarnings("resource")
    // @see ResourceDecoder.decode
    @Override
    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;
    }
    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);
        }
        if (result == null) {
            ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
            result = decodeBitmapWrapper(forBitmapDecoder, width, height);
        }
        return result;
    }
    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;
    }
}

首先,在decode()方法中,又去调用了另外一个decode()方法的重载。然后调用了decodeStream()方法,准备从服务器返回的流当中读取数据。decodeStream()方法中会先从流中读取2个字节的数据,来判断这张图是GIF图还是普通的静图,如果是GIF图就调用decodeGifWrapper()方法来进行解码,如果是普通的静图就用调用decodeBitmapWrapper()方法来进行解码。这里我们只分析普通静图的实现流程,GIF图的实现有点过于复杂了,无法在本篇文章当中分析。

然后我们来看一下decodeBitmapWrapper()方法,这里调用了bitmapDecoder.decode()方法。这个bitmapDecoder是一个ImageVideoBitmapDecoder对象,那么我们来看一下它的代码,如下所示:

public class ImageVideoBitmapDecoder implements ResourceDecoder {
    private final ResourceDecoder streamDecoder;
    private final ResourceDecoder fileDescriptorDecoder;
 
    public ImageVideoBitmapDecoder(ResourceDecoder streamDecoder,
            ResourceDecoder fileDescriptorDecoder) {
        this.streamDecoder = streamDecoder;
        this.fileDescriptorDecoder = fileDescriptorDecoder;
    }
    @Override
    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;
    }
}

上面调用了source.getStream()来获取到服务器返回的InputStream,然后调用streamDecoder.decode()方法进行解码。streamDecode是一个StreamBitmapDecoder对象,那么我们再来看这个类的源码,如下所示:

public class StreamBitmapDecoder implements ResourceDecoder {
    private final Downsampler downsampler;
    private BitmapPool bitmapPool;
    private DecodeFormat decodeFormat;
    public StreamBitmapDecoder(Downsampler downsampler, BitmapPool bitmapPool, DecodeFormat decodeFormat) {
        this.downsampler = downsampler;
        this.bitmapPool = bitmapPool;
        this.decodeFormat = decodeFormat;
    }
    @Override
    public Resource decode(InputStream source, int width, int height) {
        Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
        return BitmapResource.obtain(bitmap, bitmapPool);
    }
}

当然这里其实处理了很多的逻辑,包括对图片的压缩,甚至还有旋转、圆角等逻辑处理,但是我们目前只需要关注主线逻辑就行了。decode()方法执行之后,会返回一个Bitmap对象,那么图片在这里其实也就已经被加载出来了,剩下的工作就是如果让这个Bitmap显示到界面上。回到刚才的StreamBitmapDecoder当中,你会发现,它的decode()方法返回的是一个Resource对象。而我们从Downsampler中得到的是一个Bitmap对象,因此这里又调用了BitmapResource.obtain()方法,将Bitmap对象包装成了Resource对象。代码如下所示:

public class BitmapResource implements Resource {
    private final Bitmap bitmap;
    private final BitmapPool bitmapPool;
    public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) {
        if (bitmap == null) {
            return null;
        } else {
            return new BitmapResource(bitmap, bitmapPool);
        }
    }
    public BitmapResource(Bitmap bitmap, BitmapPool bitmapPool) {
        if (bitmap == null) {
            throw new NullPointerException("Bitmap must not be null");
        }
        if (bitmapPool == null) {
            throw new NullPointerException("BitmapPool must not be null");
        }
        this.bitmap = bitmap;
        this.bitmapPool = bitmapPool;
    }
    @Override
    public Bitmap get() {
        return bitmap;
    }
    @Override
    public int getSize() {
        return Util.getBitmapByteSize(bitmap);
    }
    @Override
    public void recycle() {
        if (!bitmapPool.put(bitmap)) {
            bitmap.recycle();
        }
    }
}

BitmapResource的源码也非常简单,经过这样一层包装之后,如果我还需要获取Bitmap,只需要调用Resource的get()方法就可以了。然后我们需要一层层继续向上返回,StreamBitmapDecoder会将值返回到ImageVideoBitmapDecoder当中,而ImageVideoBitmapDecoder又会将值返回到GifBitmapWrapperResourceDecoder的decodeBitmapWrapper()方法当中。由于代码隔得有点太远了,我重新把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;
}

可以看到,decodeBitmapWrapper()方法返回的是一个GifBitmapWrapper对象。因此,这里又将Resource封装到了一个GifBitmapWrapper对象当中。这个GifBitmapWrapper顾名思义,就是既能封装GIF,又能封装Bitmap,从而保证了不管是什么类型的图片Glide都能从容应对。我们顺便来看下GifBitmapWrapper的源码吧,如下所示:

public class GifBitmapWrapper {
    private final Resource gifResource;
    private final Resource bitmapResource;
    public GifBitmapWrapper(Resource bitmapResource, Resource gifResource) {
        if (bitmapResource != null && gifResource != null) {
            throw new IllegalArgumentException("Can only contain either a bitmap resource or a gif resource, not both");
        }
        if (bitmapResource == null && gifResource == null) {
            throw new IllegalArgumentException("Must contain either a bitmap resource or a gif resource");
        }
        this.bitmapResource = bitmapResource;
        this.gifResource = gifResource;
    }
    public int getSize() {
        if (bitmapResource != null) {
            return bitmapResource.getSize();
        } else {
            return gifResource.getSize();
        }
    }
    public Resource getBitmapResource() {
        return bitmapResource;
    }
    public Resource getGifResource() {
        return gifResource;
    }
}

还是比较简单的,就是分别对gifResource和bitmapResource做了一层封装而已,相信没有什么解释的必要。

然后,这个GifBitmapWrapper对象会一直向上返回,返回到GifBitmapWrapperResourceDecoder最外层的decode()方法的时候,会对它再做一次封装,如下所示:

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

可以看到,这里又将GifBitmapWrapper封装到了一个GifBitmapWrapperResource对象当中,最终返回的是一个Resource对象。这个GifBitmapWrapperResource和刚才的BitmapResource是相似的,它们都实现的Resource接口,都可以通过get()方法来获取封装起来的具体内容。GifBitmapWrapperResource的源码如下所示:

public class GifBitmapWrapperResource implements Resource {
    private final GifBitmapWrapper data;
 
    public GifBitmapWrapperResource(GifBitmapWrapper data) {
        if (data == null) {
            throw new NullPointerException("Data must not be null");
        }
        this.data = data;
    }
    @Override
    public GifBitmapWrapper get() {
        return data;
    }
    @Override
    public int getSize() {
        return data.getSize();
    }
    @Override
    public void recycle() {
        Resource bitmapResource = data.getBitmapResource();
        if (bitmapResource != null) {
            bitmapResource.recycle();
        }
        Resource gifDataResource = data.getGifResource();
        if (gifDataResource != null) {
            gifDataResource.recycle();
        }
    }
}

经过这一层的封装之后,我们从网络上得到的图片就能够以Resource接口的形式返回,并且还能同时处理Bitmap图片和GIF图片这两种情况。

现在回到DecodeJob,它的decodeFromSourceData()方法返回的是一个Resource对象,其实也就是Resource对象。然后继续向上返回,最终返回到decodeFromSource()方法当中,如下所示。

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

刚才我们就是从这里跟进到decodeSource()方法当中,然后执行了一大堆一大堆的逻辑,最终得到了这个Resource对象。然而你会发现,decodeFromSource()方法最终返回的却是一个Resource对象,那么这到底是怎么回事呢?我们就需要跟进到transformEncodeAndTranscode()方法来瞧一瞧了,代码如下所示:

private Resource transformEncodeAndTranscode(Resource decoded) {
    long startTime = LogTime.getLogTime();
    Resource transformed = transform(decoded);
    writeTransformedToCache(transformed);
    startTime = LogTime.getLogTime();
    Resource result = transcode(transformed);
    return result;
}
private Resource transcode(Resource transformed) {
    if (transformed == null) {
        return null;
    }
    return transcoder.transcode(transformed);
}

首先,这里调用了一个transcode()方法,就把Resource对象转换成Resource对象。而transcode()方法中又是调用了transcoder.transcode(),那么这个transcoder是什么呢?就是在第二步load()方法返回的那个DrawableTypeRequest对象,它的构建函数中去构建了一个FixedLoadProvider对象,然后我们将三个参数传入到了FixedLoadProvider当中,其中就有一个GifBitmapWrapperDrawableTranscoder对象。后来在onSizeReady()方法中获取到了这个参数,并传递到了Engine当中,然后又由Engine传递到了DecodeJob当中。因此,这里的transcoder其实就是这个GifBitmapWrapperDrawableTranscoder对象。那么我们来看一下它的源码:

public class GifBitmapWrapperDrawableTranscoder implements ResourceTranscoder {
    private final ResourceTranscoder bitmapDrawableResourceTranscoder;
 
    public GifBitmapWrapperDrawableTranscoder(
            ResourceTranscoder bitmapDrawableResourceTranscoder) {
        this.bitmapDrawableResourceTranscoder = bitmapDrawableResourceTranscoder;
    }
 
    @Override
    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();
        }
        return (Resource) result;
    }
}

GifBitmapWrapperDrawableTranscoder的核心作用就是用来转码的。因为GifBitmapWrapper是无法直接显示到ImageView上面的,只有Bitmap或Drawable才能显示到ImageView上。因此,这里的transcode()方法先从Resource中取出GifBitmapWrapper对象,然后再从GifBitmapWrapper中取出Resource对象。然后判断,如果Resource为空,那么说明此时加载的是GIF图,直接调用getGifResource()方法将图片取出即可,因为Glide用于加载GIF图片是使用的GifDrawable这个类,它本身就是一个Drawable对象了。而如果Resource不为空,那么就需要再做一次转码,将Bitmap转换成Drawable对象才行,因为要保证静图和动图的类型一致性,不然逻辑上是不好处理的。这里又进行了一次转码,是调用的GlideBitmapDrawableTranscoder对象的transcode()方法,代码如下所示:

public class GlideBitmapDrawableTranscoder implements ResourceTranscoder {
    private final Resources resources;
    private final BitmapPool bitmapPool;
 /..
    @Override
    public Resource transcode(Resource toTranscode) {
        GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
        return new GlideBitmapDrawableResource(drawable, bitmapPool);
    }
 
}

可以看到,这里new了一个GlideBitmapDrawable对象,并把Bitmap封装到里面。然后对GlideBitmapDrawable再进行一次封装,返回一个Resource对象。现在再返回到GifBitmapWrapperDrawableTranscoder的transcode()方法中,你会发现它们的类型就一致了。因为不管是静图的Resource对象,还是动图的Resource对象,它们都是属于父类Resource对象的。因此transcode()方法也是直接返回了Resource,而这个Resource其实也就是转换过后的Resource了。

继续回到DecodeJob,它的decodeFromSource()方法得到了Resource对象,当然也就是Resource对象。然后继续向上返回会回到EngineRunnable的decodeFromSource()方法,再回到decode()方法,再回到run()方法当中。那么我们重新再贴一下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);
    }
}

也就是说,经过decode()方法的执行,我们最终得到了这个Resource对象,那么接下来就是如何将它显示出来了。可以看到,这里调用了onLoadComplete()方法,表示图片加载已经完成了,代码如下所示:

class EngineJob implements EngineRunnable.EngineRunnableManager {
 
    private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
    private final List cbs = new ArrayList();
 
    public void addCallback(ResourceCallback cb) {
        Util.assertMainThread();
        if (hasResource) {
            cb.onResourceReady(engineResource);
        } else if (hasException) {
            cb.onException(exception);
        } else {
            cbs.add(cb);
        }
    }
 
    @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;
        engineResource.acquire();
        listener.onEngineJobComplete(key, engineResource);
        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                cb.onResourceReady(engineResource);
            }
        }
        engineResource.release();
    }
 
    @Override
    public void onException(final Exception e) {
        this.exception = e;
        MAIN_THREAD_HANDLER.obtainMessage(MSG_EXCEPTION, this).sendToTarget();
    }
 
    private void handleExceptionOnMainThread() {
        if (isCancelled) {
            return;
        } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received an exception without any callbacks to notify");
        }
        hasException = true;
        listener.onEngineJobComplete(key, null);
        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                cb.onException(exception);
            }
        }
    }
    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发出了一条MSG_COMPLETE消息,那么在MainThreadCallback的handleMessage()方法中就会收到这条消息。从这里开始,所有的逻辑又回到主线程当中进行了,因为很快就需要更新UI了。然后,调用了handleResultOnMainThread()方法,这个方法中又通过一个循环,调用了所有ResourceCallback的onResourceReady()方法。那么这个ResourceCallback是什么呢?答案在addCallback()方法当中,它会向cbs集合中去添加ResourceCallback。那么这个addCallback()方法又是哪里调用的呢?其实调用的地方我们早就已经看过了,只不过之前没有注意,现在重新来看一下Engine的load()方法,如下所示:

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
 
    public  LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
            DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder transcoder, Priority priority, 
            boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
 
        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        DecodeJob decodeJob = new DecodeJob(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);
    }
}

注意EngineJob.addCallback()方法来注册的一个ResourceCallback。那么接下来的问题就是,Engine.load()方法的ResourceCallback参数又是谁传过来的呢?这就需要回到GenericRequest的onSizeReady()方法当中了,我们看到ResourceCallback是load()方法的最后一个参数,那么在onSizeReady()方法中调用load()方法时传入的最后一个参数是什么?代码如下所示:

public final class GenericRequest implements Request, SizeReadyCallback,
        ResourceCallback {
    @Override
    public void onSizeReady(int width, int height) {
        if (status != Status.WAITING_FOR_SIZE) {
            return;
        }
        status = Status.RUNNING;
        width = Math.round(sizeMultiplier * width);
        height = Math.round(sizeMultiplier * height);
        ModelLoader modelLoader = loadProvider.getModelLoader();
        final DataFetcher dataFetcher = modelLoader.getResourceFetcher(model, width, height);
        ResourceTranscoder transcoder = loadProvider.getTranscoder();
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, 
                transcoder, priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
    }
}

GenericRequest本身就实现了ResourceCallback的接口,因此EngineJob的回调最终其实就是回调到了GenericRequest的onResourceReady()方法当中了,代码如下所示:

public void onResourceReady(Resource resource) {
    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
        releaseResource(resource);
        return;
    }
    if (!canSetResource()) {
        releaseResource(resource);
        status = Status.COMPLETE;
        return;
    }
    onResourceReady(resource, (R) received);
}
private void onResourceReady(Resource resource, R result) {
    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();
}

这里有两个onResourceReady()方法,首先在第一个onResourceReady()方法当中,调用resource.get()方法获取到了封装的图片对象,也就是GlideBitmapDrawable对象,或者是GifDrawable对象。然后将这个值传入到了第二个onResourceReady()方法当中,并在第36行调用了target.onResourceReady()方法。

那么这个target又是什么呢?这个又需要向上翻很久了,在第三步into()方法的一开始,我们就分析了在into()方法的最后一行,调用了glide.buildImageViewTarget()方法来构建出一个Target,而这个Target就是一个GlideDrawableImageViewTarget对象。

那么我们去看GlideDrawableImageViewTarget的源码就可以了,如下所示:

public class GlideDrawableImageViewTarget extends ImageViewTarget {
    private static final float SQUARE_RATIO_MARGIN = 0.05f;
    private int maxLoopCount;
    private GlideDrawable resource;
    public GlideDrawableImageViewTarget(ImageView view) {
        this(view, GlideDrawable.LOOP_FOREVER);
    }
    public GlideDrawableImageViewTarget(ImageView view, int maxLoopCount) {
        super(view);
        this.maxLoopCount = maxLoopCount;
    }
    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation animation) {
        if (!resource.isAnimated()) {
            float viewRatio = view.getWidth() / (float) view.getHeight();
            float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
            if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
                    && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
                resource = new SquaringDrawable(resource, view.getWidth());
            }
        }
        super.onResourceReady(resource, animation);
        this.resource = resource;
        resource.setLoopCount(maxLoopCount);
        resource.start();
    }
    @Override
    protected void setResource(GlideDrawable resource) {
        view.setImageDrawable(resource);
    }
    @Override
    public void onStart() {
        if (resource != null) {
            resource.start();
        }
    }
    @Override
    public void onStop() {
        if (resource != null) {
            resource.stop();
        }
    }
}

在GlideDrawableImageViewTarget的onResourceReady()方法中做了一些逻辑处理,包括如果是GIF图片的话,就调用resource.start()方法开始播放图片,但是好像并没有看到哪里有将GlideDrawable显示到ImageView上的逻辑。

确实没有,不过父类里面有,这里在第25行调用了super.onResourceReady()方法,GlideDrawableImageViewTarget的父类是ImageViewTarget,我们来看下它的代码吧:

public abstract class ImageViewTarget extends ViewTarget implements GlideAnimation.ViewAdapter {
    @Override
    public void onResourceReady(Z resource, GlideAnimation glideAnimation) {
        if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
            setResource(resource);
        }
    }
 
    protected abstract void setResource(Z resource);
 
}

可以看到,在ImageViewTarget的onResourceReady()方法当中调用了setResource()方法,而ImageViewTarget的setResource()方法是一个抽象方法,具体的实现还是在子类那边实现的。

那子类的setResource()方法是怎么实现的呢?回头再来看一下GlideDrawableImageViewTarget的setResource()方法,没错,调用的view.setImageDrawable()方法,而这个view就是ImageView。代码执行到这里,图片终于也就显示出来了。

那么,我们对Glide执行流程的源码分析,到这里也终于结束了。

总结

  1. with()方法的作用:通过RequestManagerRetriever的单例静态get方法拿到对象实例,调用成员函数get方法,通过getApplicationManager(Context)方法返回RequestManager实例。
  2. load()方法的作用:fromString----->loadGeneric------->返回asBitmap相关的DrawableTypeRequest对象----->调用DrawableRequestBuilder父类中load方法------>给父类成员变量赋值-------->最后再RequestManager类中将DrawableRequestBuilder父类对象强转成子类DrawableTypeRequest,也就是说,load方法最终是得到了DrawableTypeRequest对象。
  3. into()方法的作用:①初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),②使用最原始的HTTPConnect网络连接,读取文件流,③根据文件判断是GIF动图还是Bitmap静态图片,④通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件。

 

补充,Glide缓存机制:

Glide的缓存分为两种,Resource缓存、Bitmap缓存。
一、Resource缓存:首先Resource缓存就是缓存整体的图片资源文件,缓存它是为了当首次从服务器端下载下来之后,缓存到本地,如果再次使用这个图片,不用去跑网络请求,直接从本地读取,节省流量也提高访问速度。它使用的是三级缓存原理:

一级缓存:内存缓存,缓存被回收的资源,使用LRU算法(Least Frequently Used,最近最少使用算法),当需要再次使用到被回收的资源时,直接从内存中读取;
二级缓存:使用弱引用缓存正在使用的资源,当系统执行GC操作时,会回收没有强引用的资源。使用弱引用缓存,既可以缓存当前正在强引用使用的资源,又不阻碍系统回收无引用的资源
三级缓存:磁盘缓存,网络图片下载成功后,以文件的形式缓存到磁盘中
1和2都是内存缓存,只不过功能不一样,1是使用LRU算法缓存被GC回收的资源,2是用弱引用缓存正在使用的资源。在复用图片资源的时候首先从回收的内存缓存集合中查找,内存缓存的集合中没有的时候,去弱引用集合查找是否是当前正在使用,没有的话,去磁盘中查找,再没有的时候去网络中查找。

二、Bitmap缓存:Bitmap所占的内存大小由其三部分组成:图片宽,高和Bitmap质量参数。

bitmap内存大小 = 宽*高*质量参数所占的位数   ,单位是字节b

  1. ALPHA—8就是Alpha是由8位组成的(1B)
  2. ARGB_4444,4个4位组成16位(2B)
  3. ARGB_8888,4个8位组成32位(4B)
  4. RGB_565,R是5位,G是6位,B是5位组成16位(2B),Glide默认bitmap压缩参数就是这个RGB_565,但是它不能显示透明度

先说一下为什么要进行bitmap压缩,比如在recycleView中加载大量的图片,频繁的创建和回收Bitmap会导致内存波动影响性能,既然这样,我们能不能缓存Bitmap,不要让它老是new和销毁,这应该是Glide去做Bitmap缓存的原因,

Bitmap缓存算法:在Glide中使用BitmapPool来缓存Bitmap,使用的也是LRU算法(最近最少使用算法),当需要使用Bitmap时,先从Bitmap的池子中选取,如果找不到合适的Bitmap,再去创建,当使用完毕后,不再直接调用Bitmap.recycle()释放内存,而是缓存到Bitmap池子里。

Bitmap的缓存是以键值对的方式进行缓存的,Resource和Bitmap都作为Value,而这些值是需要一个key来标识缓存的内容,根据key可以查找和移除对应的缓存。

参考链接:https://blog.csdn.net/dream_caoyun/article/details/81510582

你可能感兴趣的:(Android)