小菜读Glide3.0源码----into()

我进尽量不打错别字,用词准确,不造成阅读障碍。

本文基于Glide3.7.0源码,并不是4.0系列。本系列分为三部分:with(…)、load(…)、into(…);本篇文章只介绍into(…)这一个步骤,前两个步骤相对而言比较简单,特别是with(…),而into(…)内容非常复杂,必须单独开一篇,要不然太长了。关于with(…)和load(…)的文章在这里小菜读Glide3.0 源码----with()和load(), 本文的主要目的在于学习总结,并给需要的人一点帮助,并不奢望多么完美,如有错误,欢迎指出。

一.准备

我们使用最简单的例子:

Glide.with(this).load("字符串地址").into(imageView);  //this为Activity

我们分析的是最简单的情况,再复杂一点的我就不能保证正确了,哭~~!

Glide源码阅读3+3+3(我自己整理的)中这是第一个"3"中最后一步,也包含了最后一个"3"中的全部。

二.into()

我们还记得load()方法最后返回的是DrawableTypeRequest对象,而这个对象是没有into()方法的,但是它继承了DrawableRequestBuilder类,这个类中是有into()方法的,所以我们看看DrawableRequestBuilder中的into()方法。

//DrawableRequestBuilder.class
public Target<GlideDrawable> into(ImageView view) {
        return super.into(view);
}

很简单的调用父类into()方法,返回一个Target,默认是GlideDrawable类型,Target只是有个接口,所以就要返回实现了这个接口的类的对象,往后面看,就知道这个Target是什么了。其父类为GenericRequestBuilder,看名字也看出来这两者是有关系的。

//GenericRequestBuilder.class
public Target<TranscodeType> into(ImageView view) {
        Util.assertMainThread();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null View");
        } else {
            if (!this.isTransformationSet && view.getScaleType() != null) {
                switch(view.getScaleType()) {
                case CENTER_CROP:
                    this.applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    this.applyFitCenter();
                }
            }
            return this.into(this.glide.buildImageViewTarget(view, this.transcodeClass));
        }
    }

​ 嗯,返回一个Target对象,TranscodeType是什么?翻译过来是转码类型,是在类构造方法里面被设置的,默认是GlideDrawable,这个不讲太多,后面就明白了。

​ 首先是确保运行在主线程,如果不是,就直接抛异常:throw new IllegalArgumentException(“You must call this method on the main thread”); 然后是判断view是否为null,是则抛异常,不是则继续,判断有没有设置填充方式,我们知道ImageView是有填充方式的,不同的填充方式效果差很远,计算的东西也不一样,这里是Glide代码细研究的地方,暂且不论,看后面,this.into(this.glide.buildImageViewTarget(view, this.transcodeClass));。 先看this.glide.buildImageViewTarget(view,this.transcodeClass);看名字是build一个Target,参数view不必说,transcodeClass就是默认的GlideDrawable.Class,上一篇文章讲过了,Glide这个类在构造方法里面注册了超多的Factory,其中就有imageViewTargetFactory,所以这个build…Target(…)其实是调用ImageViewFactory的buildTarget(…)方法:

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

所以说默认是GlideDrawableImageViewTarget。其它的,看名字还有一个Bitmap,这个你要指定Bitmap才可以,至于DrawableImageViewTarget,一般用不到。target翻译过来是目标的意思,也就是说我们传进来的imageView,被我们包装成了target,也就是我们的目标,为什么要这样,往后面看。

回到这里:

return this.into(this.glide.buildImageViewTarget(view, this.transcodeClass));

Target搞定了,又调用了另一个into(…):

//GenericRequestBuilder.class
public <Y extends Target<TranscodeType>> Y into(Y target) {
        Util.assertMainThread();
        if (target == null) {
            throw new IllegalArgumentException("You must pass in a non null Target");
        } else if (!this.isModelSet) {
            throw new IllegalArgumentException("You must first set a model (try #load())");
        } else {
            Request previous = target.getRequest();
            if (previous != null) {
                previous.clear();
                this.requestTracker.removeRequest(previous);
                previous.recycle();
            }

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

​ 前面的不用解释了吧,主要else中的内容,这是我们3+3+3 中的第二步:清楚旧的request---->构建新的request---->运行新的request。

​ 先是获取request,如果不为null就清除,这里先不管request是什么,因为马上要构建request了,你就知道是什么了。看看buildRequest(…):

//GenericRequestBuilder.class
private Request buildRequest(Target<TranscodeType> target) {
        if (this.priority == null) {
            this.priority = Priority.NORMAL;  //优先权正常
        }
        return this.buildRequestRecursive(target, (ThumbnailRequestCoordinator)null);
    }

再看看buildRequestRecursive(…)方法:

//GenericRequestBuilder.class
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
        ThumbnailRequestCoordinator coordinator;
        Request fullRequest;
        Request thumbRequest;
        if (this.thumbnailRequestBuilder != null) {
            if (this.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()");
            } else {
                if (this.thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
                    this.thumbnailRequestBuilder.animationFactory = this.animationFactory;
                }

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

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

                coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
                fullRequest = this.obtainRequest(target, this.sizeMultiplier, this.priority, coordinator);
                this.isThumbnailBuilt = true;
                thumbRequest = this.thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
                this.isThumbnailBuilt = false;
                coordinator.setRequests(fullRequest, thumbRequest);
                return coordinator;
            }
        } else if (this.thumbSizeMultiplier != null) {
            coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
            fullRequest = this.obtainRequest(target, this.sizeMultiplier, this.priority, coordinator);
            thumbRequest = this.obtainRequest(target, this.thumbSizeMultiplier, this.getThumbnailPriority(), coordinator);
            coordinator.setRequests(fullRequest, thumbRequest);
            return coordinator;
        } else {
            return this.obtainRequest(target, this.sizeMultiplier, this.priority, parentCoordinator);
        }
    }

前面大部分都是压缩和对缩略图的处理,我没研究,举例中是没有压缩的,那么就会走到最后一个else下:

return this.obtainRequest(target, this.sizeMultiplier, this.priority, parentCoordinator);

不得不感慨一句,GenericRequestBulider这个类真是强大,我们已经在里面走了很久了,还没出来。好了,我们看一下obtainRequest(…)吧:

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

​ 终于要从GenericRequestBuilder.java 中出来了。先整理一下前面的:我们直接就进入到了GenericRequestBuilder.java 中,在其中主要调用了buildImageViewTarget(…)方法,返回一个GlideDrawableTarget对象,然后找到了第二个"3"的入口:清除request—>构建新的request—>运行新request,最后还有压缩和缩略图处理,如果没有压缩,就到现在的obtainRequest。可以看到调用了GenericRequest.obtain(…),里面传入了非常多的参数,熟悉的loadProvide、model、context、target、placeholderDrawable、placeholderId、diskCacheStrategy等等,很多,看一下:

//GenericRequest.class
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(LoadProvider<A, T, Z, R> loadProvider, A model, Key signature, Context context, Priority priority, Target<R> target, float sizeMultiplier, Drawable placeholderDrawable, int placeholderResourceId, Drawable errorDrawable, int errorResourceId, Drawable fallbackDrawable, int fallbackResourceId, RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, Class<R> transcodeClass, boolean isMemoryCacheable, GlideAnimationFactory<R> animationFactory, int overrideWidth, int overrideHeight, DiskCacheStrategy diskCacheStrategy) {
        
  GenericRequest<A, T, Z, R> 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;
    }

主要是从消息池里面poll()一个request对象,没有就new一个,然后调用request的init()方法,因为request就是本身类的对象引用,所以我们直接看init(…)方法,之前传的好多参数全都传入进来了:

//GenericRequest.class
private void init(LoadProvider<A, T, Z, R> loadProvider, A model, Key signature, Context context, Priority priority, Target<R> target, float sizeMultiplier, Drawable placeholderDrawable, int placeholderResourceId, Drawable errorDrawable, int errorResourceId, Drawable fallbackDrawable, int fallbackResourceId, RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, Class<R> transcodeClass, boolean isMemoryCacheable, GlideAnimationFactory<R> animationFactory, int overrideWidth, int overrideHeight, DiskCacheStrategy diskCacheStrategy) {
        this.loadProvider = loadProvider;
        this.model = model;
        //...全是this.xxx = xxx;
        if (model != null) {
            check("ModelLoader", loadProvider.getModelLoader(), "try .using(ModelLoader)");
            check("Transcoder", loadProvider.getTranscoder(), "try .as*(Class).transcode(ResourceTranscoder)");
            check("Transformation", transformation, "try .transform(UnitTransformation.get())");
            if (diskCacheStrategy.cacheSource()) {
                check("SourceEncoder", loadProvider.getSourceEncoder(), "try .sourceEncoder(Encoder) or .diskCacheStrategy(NONE/RESULT)");
            } else {
                check("SourceDecoder", loadProvider.getSourceDecoder(), "try .decoder/.imageDecoder/.videoDecoder(ResourceDecoder) or .diskCacheStrategy(ALL/SOURCE)");
            }

            if (diskCacheStrategy.cacheSource() || diskCacheStrategy.cacheResult()) {
                check("CacheDecoder", loadProvider.getCacheDecoder(), "try .cacheDecoder(ResouceDecoder) or .diskCacheStrategy(NONE)");
            }

            if (diskCacheStrategy.cacheResult()) {
                check("Encoder", loadProvider.getEncoder(), "try .encode(ResourceEncoder) or .diskCacheStrategy(NONE/SOURCE)");
            }
        }
    }

中间省略了好多this.xxx = xxx,也就是属性赋值,往后就是检查一些属性配置;到这里我们"buildRequest"这一步就完事了,最后返回一个Request对象,总的来说就是各种赋值并检测,构建一个Request对象。接下来是"3"步中的最后一步,runRequest(…);先会看一下代码:

//GenericRequestBuilder.class
//..省略
Request request = this.buildRequest(target);
            target.setRequest(request);
            this.lifecycle.addListener(target);
            this.requestTracker.runRequest(request);
            return target;

在run之前,先setRequest一下,在addListener一下,这两部跟我们的run关系不大。我们直接看runRequest(…)吧:

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

如果没有暂停,就使用request.begin()方法,由于我们是GenericRequest ,所以直接看GenericRequest 的begin()方法:

//GenericRequest.class
public void begin() {
        this.startTime = LogTime.getLogTime();
        if (this.model == null) {
            this.onException((Exception)null);
        } else {
            this.status = GenericRequest.Status.WAITING_FOR_SIZE;
            if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
                this.onSizeReady(this.overrideWidth, this.overrideHeight);
            } else {
                this.target.getSize(this);
            }
            if (!this.isComplete() && !this.isFailed() && this.canNotifyStatusChanged()) {
                this.target.onLoadStarted(this.getPlaceholderDrawable());
            }
           //...
            }
        }
    }

先验证图片的尺寸是否有效,一般是指定了大小,合格了就会this.onSizeReady(…);如果没有指定,经过一番处理还是会调用onSizeReady(…)(感觉这里会出一道面试题,问你怎么计算的),这个方法里面我先大体说一下,从缓存拿数据、从网络拿数据都是这里作为入口,我们先想一下,从缓存读数据和从网络获取数据应该都是异步的,所以我们在获取到图片资源这段时间要干什么呢?没错,就是往下走,会走到this.targetonLoadStarted(…)方法,将placeholder设置的图片拿出来放进去,要是你写,你也会这么写吧!你可以跟一下,很简单,最后会调用ImageViewTarget 的onLoadStarted()方法,看一下:

public void onLoadStarted(Drawable placeholder) {
        ((ImageView)this.view).setImageDrawable(placeholder);
}

哈哈,就是设置等待时的图片,现在我们可以回来看一看this.onSizeReady(…)干嘛了:

//GenericRequest.class
public void onSizeReady(int width, int height) {
      //...log打印
        if (this.status == GenericRequest.Status.WAITING_FOR_SIZE) {
            this.status = GenericRequest.Status.RUNNING;
            width = Math.round(this.sizeMultiplier * (float)width);
            height = Math.round(this.sizeMultiplier * (float)height);
            ModelLoader<A, T> modelLoader = this.loadProvider.getModelLoader();
            DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(this.model, width, height);
            if (dataFetcher == null) {
                this.onException(new Exception("Failed to load model: '" + this.model + "'"));
            } else {
                ResourceTranscoder<Z, R> transcoder = this.loadProvider.getTranscoder();
              //...log打印
                }
                this.loadedFromMemoryCache = true;
                this.loadStatus = this.engine.load(this.signature, width, height, dataFetcher, this.loadProvider, this.transformation, transcoder, this.priority, this.isMemoryCacheable, this.diskCacheStrategy, this);
                this.loadedFromMemoryCache = this.resource != null;
               //...log打印
                }
            }
        }
    }

前面的部分其实都是三大步中load(…)那步涉及的操作,现在把它们取出来,建议自己看看,后面文章还要再讲讲,我们直接看看this.engine.load(…),之前的操作最后都会集中到这里:

//Engine.class
public <T, Z, R> Engine.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();
        String id = fetcher.getId();
        EngineKey key = this.keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder());
        EngineResource<?> cached = this.loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            //...log打印
            return null;
        } else {
            EngineResource<?> active = this.loadFromActiveResources(key, isMemoryCacheable);
            if (active != null) {
                cb.onResourceReady(active);
                //...log打印
                return null;
            } else {
                EngineJob current = (EngineJob)this.jobs.get(key);
                if (current != null) {
                    current.addCallback(cb);
                    //...log打印
                    return new Engine.LoadStatus(cb, current);
                } else {
                    EngineJob engineJob = this.engineJobFactory.build(key, isMemoryCacheable);
                    DecodeJob<T, Z, R> decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation, transcoder, this.diskCacheProvider, diskCacheStrategy, priority);
                    EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
                    this.jobs.put(key, engineJob);
                    engineJob.addCallback(cb);
                    engineJob.start(runnable);
                    //...log打印
                    return new Engine.LoadStatus(cb, engineJob);
                }
            }
        }
    }

显示检查是否在Main线程,然后是从内存缓存拿数据,loadFromCache和loadFromActiveResources都是从缓存拿数据,只是后者是从活跃缓存区拿数据,这就涉及到Glide的缓存机制了,考虑本文只是流程梳理,就不在多说了,后面会再写一篇文章写的。如果缓存中有数据,就直接callback.onResourceReady(…);callback就是GenericRequest.class,看名字也知道是回调,可以自己去看看。正常缓存是没有的,this.jobs就是一个map,自己去看看,重点是创建了一个Runnable,然后start这个runnable,直接看runnable中的run(…)干了什么:

//EngineRunnable.class
public void run() {
        if (!this.isCancelled) {
            Exception exception = null;
            Resource resource = null;
            try {
                resource = this.decode();
            } catch (Exception var4) {
               //...log打印
                exception = var4;
            }
            if (this.isCancelled) {
                if (resource != null) {
                    resource.recycle();
                }
            } else {
                if (resource == null) {
                    this.onLoadFailed(exception);
                } else {
                    this.onLoadComplete(resource);
                }
            }
        }
    }

上来就decode(),然后就recycle(),解码?回收?看看解码吧,怎么就解码了,解什么码?

//EngineRunnable.class 
private Resource<?> decode() throws Exception {
        return this.isDecodingFromCache() ? this.decodeFromCache() : this.decodeFromSource();
    }

看函数名字,一个从缓存解码,一个从Source解码,缓存就不说了,看看后者吧,后者会调用decodeJob.decodeFromSource():

//DecodeJob.class
public Resource<Z> decodeFromSource() throws Exception {
        Resource<T> decoded = this.decodeSource();  //包含网络访问
        return this.transformEncodeAndTranscode(decoded);  //数据转换
    }

看注释,直接看网络访问吧:

//DecodeJob.class
private Resource<T> decodeSource() throws Exception {
        Resource decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            A data = this.fetcher.loadData(this.priority); //这是重点
           //...log打印
            if (this.isCancelled) {
                Object var5 = null;
                return (Resource)var5;
            }
            decoded = this.decodeFromSourceData(data);
        } finally {
            this.fetcher.cleanup();
        }
        return decoded;
    }

就是将data进行解码,然后返回解码结果,那么data是怎么来的?答案就在this.fetcher.loadData(…);,进去看看,往回跟,最后发现是ImageVideoModelLoader的loadData(…):

//ImageVideoModelLoader.class 
public ImageVideoWrapper loadData(Priority priority) throws Exception {
            InputStream is = null;
            if (this.streamFetcher != null) {
                try {
                    is = (InputStream)this.streamFetcher.loadData(priority);
                } catch (Exception var6) {
                    //...log打印
                    }
                    if (this.fileDescriptorFetcher == null) {
                        throw var6;
                    }
                }
            }
            ParcelFileDescriptor fileDescriptor = null;
            if (this.fileDescriptorFetcher != null) {
                try {
                    fileDescriptor = (ParcelFileDescriptor)this.fileDescriptorFetcher.loadData(priority);
                } catch (Exception var5) {
                     //...log打印
                    if (is == null) {
                        throw var5;
                    }
                }
            }
            return new ImageVideoWrapper(is, fileDescriptor);
        }

好像看到了不得了的东西,InputStream ! ! !,赶紧看看streamFetcher.loadData(…);streamFetcer回跟发现是HttpUrlFetcher,这是在load(…)那步中注册的Factory生成的,直接看看其中的loadData(…);,直接调用了loadDataWithRedirects(…):

//HttpUrlFetcher.class
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
        if (redirects >= 5) {
            throw new IOException("Too many (> 5) redirects!");
        } else {
            try {
                if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
                    throw new IOException("In re-direct loop");
                }
            } catch (URISyntaxException var8) {
                ;
            }
            this.urlConnection = this.connectionFactory.build(url);
            Iterator i$ = headers.entrySet().iterator();
            while(i$.hasNext()) {
                Entry<String, String> headerEntry = (Entry)i$.next();
                this.urlConnection.addRequestProperty((String)headerEntry.getKey(), (String)headerEntry.getValue());
            }
            this.urlConnection.setConnectTimeout(2500);
            this.urlConnection.setReadTimeout(2500);
            this.urlConnection.setUseCaches(false);
            this.urlConnection.setDoInput(true);
            this.urlConnection.connect();
            if (this.isCancelled) {
                return null;
            } else {
                int statusCode = this.urlConnection.getResponseCode();
                if (statusCode / 100 == 2) {
                    return this.getStreamForSuccessfulRequest(this.urlConnection);
                } else if (statusCode / 100 == 3) {
                    String redirectUrlString = this.urlConnection.getHeaderField("Location");
                    if (TextUtils.isEmpty(redirectUrlString)) {
                        throw new IOException("Received empty or null redirect url");
                    } else {
                        URL redirectUrl = new URL(url, redirectUrlString);
                        return this.loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
                    }
                } else if (statusCode == -1) {
                    throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
                } else {
                    throw new IOException("Request failed " + statusCode + ": " + this.urlConnection.getResponseMessage());
                }
            }
        }
    }

这就是网络访问了,使用UrlConnection进行网络访问,返回一个InputStream,回头看,在ImageVideoModelLoader 中将拿到的is,new一个ImageVideoWrapper对象,还要return它,看看它在实例化时做了什么?:

//ImageVideoWrapper.class
public ImageVideoWrapper(InputStream streamData, ParcelFileDescriptor fileDescriptor) {
        this.streamData = streamData;
        this.fileDescriptor = fileDescriptor;
    }

额…好像很简单的赋值,只是将传入的参数进行了一层包装,变为一个实体对象。那我们再往回看,就要回到DecodeJob.class中了,拿到这个data后,进入decodeFromSourceData(),看名字也知道是从数据源中解码:

//DecodeJob.class
private Resource<T> decodeFromSourceData(A data) throws IOException {
        Resource decoded;
        if (this.diskCacheStrategy.cacheSource()) {
            decoded = this.cacheAndDecodeSourceData(data);
        } else {
            long startTime = LogTime.getLogTime();
            decoded = this.loadProvider.getSourceDecoder().decode(data, this.width, this.height);
          //...打印log
        }
        return decoded;
    }

先判断有没有磁盘缓存,有的话就解码并保存到磁盘里,没有的话就通过loadProvider获取解码器解码,先不要管具体是怎么解码的,要不然容易晕,现在只需要知道,拿到数据线包装成一个实体对象,然后解码,然后返回解码结果,即return decoded。现在,将解码结果进行数据转换,即transformEncodeAndTranscode(decoded)方法:

//DecodeJob.class 
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
        long startTime = LogTime.getLogTime();
        Resource<T> transformed = this.transform(decoded);
        //...log打印
        this.writeTransformedToCache(transformed);
        startTime = LogTime.getLogTime();
        Resource<Z> result = this.transcode(transformed);
       //...log打印
        return result;
    }

这个方法将转码后的资源放入到缓存中并转码,最后返回转码结果。返回结果会返回到EngineRunnable.class的decode()方法中,而这个方法会直接将结果返回到run()方法里面,然后就会执行到下面的代码:

//EngineRunnable.class
if (resource == null) {
    this.onLoadFailed(exception);
} else {
    this.onLoadComplete(resource);
}

继续看看onLoadComplete(…)方法吧:

//EngineRunnable.java

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

嗯,manager是EngineRunnableManager,这是个接口,实现这个接口的是EngineJob,所以看EngineJob的onResourceReady(…):

//EngineJob.java

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

发送了一个message消息,看看Handle接受到这个MSG_COMPLETE后会怎么样:

 job.handleResultOnMainThread(); //调用job的方法

job是EngineJob,所以看EnginJob的handleResultOnMainThread(…):

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

可以看到循环所有的CallBack,然后调用CallBack的onResourceReady(…);这里的callback之前就已经注册了,所以最后我们调用的是GenericRequest的onResourceReady(…):

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

看到调用了两个参数的onResourceReady(…)方法,该方法中有一句是核心:

//GenericRequest.java
target.onResourceReady(result, animation);

这个Target就是我们之前说的GlideDrawableImageViewTarget,这里面主要代码如下:

//GlideDrawableImageViewTarget.class
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
        if (!((GlideDrawable)resource).isAnimated()) {
            float viewRatio = (float)((ImageView)this.view).getWidth() / (float)((ImageView)this.view).getHeight();
            float drawableRatio = (float)((GlideDrawable)resource).getIntrinsicWidth() / (float)((GlideDrawable)resource).getIntrinsicHeight();
            if (Math.abs(viewRatio - 1.0F) <= 0.05F && Math.abs(drawableRatio - 1.0F) <= 0.05F) {
                resource = new SquaringDrawable((GlideDrawable)resource, ((ImageView)this.view).getWidth());
            }
        }
        super.onResourceReady(resource, animation);
        this.resource = (GlideDrawable)resource;
        ((GlideDrawable)resource).setLoopCount(this.maxLoopCount);
        ((GlideDrawable)resource).start();
    }

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

​ 首先是调用了onResourceReady(…);然后调用父类的onResourceReady(…);父类的onResourceReady(…)只是调用了抽象方法setResource(…);这个抽象方法由子类实现,又回到了GlideDrawableImageViewTarget的setResource(…);方法,随后会setImageDrawable(…);终于结束了…

​ 这篇文章比较长,必须结合代码看,否则跳来跳去就晕了。写到后来我都不想写了,所以文笔加快了许多,导致全文看起来比较不够透彻,本文最大的目的是自我学习总结,其次是给予别人一些帮助,但帮助可能不多,见谅!

​ 了解流程是没有用的,我认为Glide最重要的是缓存的处理 ,这是Glide的核心知识点,了解流程只是让我们知道什么时候用缓存,用了什么缓存等等,真正的缓存机制才是我们要学习的。

​ 如有错误,欢迎指正。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值