美文网首页
Glide的into()过程源码分析

Glide的into()过程源码分析

作者: 长远勿见 | 来源:发表于2018-09-28 17:54 被阅读0次

    和load()过程类似,最终Glide.with(context).load(url).into(imageView).的into()方法也调用的是GenericRequestBuilder类里面的into()方法。

    GenericRequestBuilder类里面的into()方法

    public Target<TranscodeType> into(ImageView view) {
            Util.assertMainThread();
            if (view == null) {
                throw new IllegalArgumentException("You must pass in a non null View");
            }
    
            if (!isTransformationSet && view.getScaleType() != null) {
                switch (view.getScaleType()) {
                    case CENTER_CROP:
                        applyCenterCrop();
                        break;
                    case FIT_CENTER:
                    case FIT_START:
                    case FIT_END:
                        applyFitCenter();
                        break;
                    //$CASES-OMITTED$
                    default:
                        // Do nothing.
                }
            }
            //调用了重载的into()方法,在重载的into()方法中传入的是Target对象
            return into(glide.buildImageViewTarget(view, transcodeClass));
        }
    

    先说一下这个Target接口。

    • Target接口:继承自LifecycleListener接口,Glide获取资源之后资源作用的目标,是一个回调接口,在Glide做完所有的加载和处理之后返回结果。在into()过程中,Glide会一直跟踪Target,并在图片加载处理之后更新Target内部的资源引用,在Target中我们可以获得加载的图片资源。

    继承关系
    Target接口->BaseTarget抽象类->ViewTarget抽象类(11)->ImageViewTarget抽象类(该抽象类还实现了GlideAnimation.ViewAdapter接口)->GlideDrawableImageViewTarget实现类/BitmapImageViewTarget实现类/DrawableImageViewTarget实现类
    11ViewTarget抽象类中还包括了一个SizeDeterminer内部类

    Target接口->BaseTarget抽象类->SimpleTarget抽象类->AppWidgetTarget实现类/NotificationTarget实现类

    继承了Target接口的SimpleTarget抽象类和ViewTarget抽象类用于自定义抽象类

    自定义Target:SimpleTarget和ViewTarget

    继承自LifecycleListener接口就很眼熟吧,对吧,继承自LifecycleListener接口后的生命周期就可以被RequestManager所监控,被ActivityFragmentLifeCycle所回调。

    看一下glide.buildImageViewTarget(view, transcodeClass);这行代码。

    Glide类中

    public class Glide {
    
        ......
        private final ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    
    <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
            return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
        }
    

    glide.buildImageViewTarget(view, transcodeClass);这行代码调用了Glide类中的buildImageViewTarget()方法,在这个方法中,调用了imageViewTargetFactory.buildTarget(imageView, transcodedClass);
    来看一下ImageViewTargetFactory 类的buildTarget()方法。

    ImageViewTargetFactory类中

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

    在ImageViewTargetFactory类中的buildTarget()方法中会根据传入的class参数来构建不同的Target对象,这个class参数其实基本上只有两种情况,如果你在使用Glide加载图片的时候调用了asBitmap()方法,那么这里就会构建出BitmapImageViewTarget对象,否则的话构建的都是GlideDrawableImageViewTarget对象。那么imageViewTargetFactory.buildTarget(imageView, transcodedClass);返回的将是GlideDrawableImageViewTarget对象。
    接着看重载的into()方法

    public <Y extends Target<TranscodeType>> Y into(Y target) {
            Util.assertMainThread();
            if (target == null) {
                throw new IllegalArgumentException("You must pass in a non null Target");
            }
            if (!isModelSet) {
                throw new IllegalArgumentException("You must first set a model (try #load())");
            }
            //target.getRequest()的过程(对应ViewTarget抽象类中的一系列方法),先判断该View的Target是否有之前的Request,有的话则释放
            Request previous = target.getRequest();
    
            if (previous != null) {
                previous.clear();
                requestTracker.removeRequest(previous);
                previous.recycle();
            }
            //1.
            Request request = buildRequest(target);
           //将新生成的Request设置到Target中
            target.setRequest(request);
            //将target加入到ActivityFragmentLifeCycle的LifeCycleListener集合中,进行生命周期管理
            lifecycle.addListener(target);
            //2.
            requestTracker.runRequest(request);
    
            return target;
        }
    

    分析一下1过程
    这个buildRequest(target)方法是GenericRequestBuilder类中的方法。

    GenericRequestBuilder类中的buildRequest(target)方法

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

    在GenericRequestBuilder类中的buildRequest(target)方法又调用了GenericRequestBuilder类中的buildRequestRecursive(target, null);方法

    private GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequestBuilder;
    
    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> thumbnail(
                GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequest) {
            if (this.equals(thumbnailRequest)) {
                throw new IllegalArgumentException("You cannot set a request as a thumbnail for itself. Consider using "
                        + "clone() on the request you are passing to thumbnail()");
            }
            this.thumbnailRequestBuilder = thumbnailRequest;
    
            return this;
        }
    private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
            if (thumbnailRequestBuilder != null) {
                if (isThumbnailBuilt) {
                    throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, "
                            + "consider using clone() on the request(s) passed to thumbnail()");
                }
                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 {
                return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
            }
        }
    

    在buildRequestRecursive()方法中,首先对缩略图及是否对Target设置参数的判断(是否使用了thumbnail()方法和sizeMultiplier()方法),如果有使用thunmnail()方法,则生成原始图片和缩略图的请求,并由ThumbnailRequestCoordinator对象来协调管理,使用了sizeMultiplier()方法,则同样的处理(前者递归的获得缩略图的Request,后者不递归),否则就只生成原始图片的请求,生成的请求Request是GenericRequest对象。

    • ThumbnailRequestCoordinator对象也是一个Request,用来协调管理缩略图和原始图片的请求。
      获取Requst是在obtainRequest()方法中,看一下这个方法。

    GenericRequestBuilder类的obtainRequest()

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

    看到在这个方法中得到了GenericRequest对象。这个GenericRequest继承了Request接口。
    回到重载的into()方法,1过程得到Request的过程分析结束。
    接下来2过程。
    requestTracker.runRequest(request);,来先看一下RequestTracker类的runRequest()方法。

    RequestTracker类的runRequest()方法

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

    看到了是调用了request.begin(),这个request就是刚刚分析的过程中得到的GenericRequest类型的request。
    进入GenericRequest类中。

    GenericRequest类中的begin()方法

    public void begin() {
            startTime = LogTime.getLogTime();
            //如果model即load()方法中传入的String字符串为空
            if (model == null) {
               //1.
                onException(null);
                return;
            }
    
            status = Status.WAITING_FOR_SIZE;
            //用override()方法设置了大小,直接进入onSizeReady()方法
            if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
                //2.
                onSizeReady(overrideWidth, overrideHeight);
            } else {
               //在这个方法进行一系列的计算后还是会调用onSizeReady()方法
                target.getSize(this);
            }
    
            if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
                target.onLoadStarted(getPlaceholderDrawable());
            }
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("finished run method in " + LogTime.getElapsedMillis(startTime));
            }
        }
    

    分析1过程,先看一下GenericRequest类的onException(null)方法。

    GenericRequest类的onException(null)方法

    public void onException(Exception e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "load failed", e);
            }
            status = Status.FAILED;
            if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
                setErrorPlaceholder(e);
            }
        }
    

    如果你在使用Glide的时候使用了GenericRequestBuilder的listener()方法,在这个listener()方法传入的是一个RequestListener接口,如下例所示;

    Glide.with(this).load(url).listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                    return false;
                }
    
                @Override
                public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            }).into(imageView);
    

    这个RequestListener接口中有两个方法,分别是 onException()和onResourceReady()方法。
    在进行到GenericRequest类的onException(null)方法时,在这个方法中,requestListener指向的是我们自己指定的RequestListener接口,在自己指定的requestListener为null或自己指定的requestListener的onException()方法返回为false时会调用GenericRequest类的setErrorPlaceholder()方法

    GenericRequest类的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);
        }
    private Drawable getFallbackDrawable() {
          if (fallbackDrawable == null && fallbackResourceId > 0) {
            fallbackDrawable = context.getResources().getDrawable(fallbackResourceId);
          }
          return fallbackDrawable;
        }
    private Drawable getErrorDrawable() {
            if (errorDrawable == null && errorResourceId > 0) {
                errorDrawable = context.getResources().getDrawable(errorResourceId);
            }
            return errorDrawable;
        }
    

    在这个setErrorPlaceholder()方法中,model为null时,则会显示fallback()方法中设置的drawable,如果没有设置fallback()方法,则会显示error()方法中设置的Drawable,如果没有设置error()方法,则会显示placeHolder()方法中设置的Drawable。
    设置drawable时调用Target.onLoadFailed()方法,onLoadFailed()方法是Target接口中设置的方法,在ImageViewTarget抽象类中进行了实现,在ImageViewTarget抽象类的onLoadFailed()方法中,就会进行调用view.setImageDrawable()方法,将Drawable设置到View中。
    1过程分析完了,接着进行2过程分析。

    GenericRequest类的onSizeReady()方法

     public void onSizeReady(int width, int height) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
            }
            if (status != Status.WAITING_FOR_SIZE) {
                return;
            }
            status = Status.RUNNING;
    
            width = Math.round(sizeMultiplier * width);
            height = Math.round(sizeMultiplier * height);
            //loadProvider指向的是ChildLoadProvider类型,最后得到的是ImageVideoModelLoader类型的
            ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
            //ImageVideoModelLoader类的getResourceFetcher()最后得到ImageVideoFetcher类型的dataFetcher
            final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
    
            if (dataFetcher == null) {
                onException(new Exception("Failed to load model: \'" + model + "\'"));
                return;
            }
            //得到GifBitmapWrapperDrawableTranscoder类型对象
            ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
            }
            loadedFromMemoryCache = true;
            //将上面得到的参数传入到Engine类的load()方法中
            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));
            }
        }
    

    上面的注释中已经很明白了,在上一篇GequestRequestBuilder类的分析中已经知道loadProvider指向的是ChildLoadProvider类型。ChildLoadProvider构造器中又传入了FixedLoadProvider对象,FixedLoadProvider对象中传入了ImageVideoModelLoader对象等。,在上一篇文中已经分析过了,过程中的一些初始化的过程以及实例变量的意义及来源。Glide中很早的初始化一些东西,很早初始化的这些东西又传入到后面的方法中,这个要注意。
    好滴,onSizeReady()方法中最重要的就是调用了Engine的load()方法,进入这个方法看看。

    Engine的load()方法

    private final EngineJobFactory engineJobFactory;
    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 engineJob = engineJobFactory.build(key, isMemoryCacheable);
             //这个fetcher就是在GenericRequest类中得到的ImageVideoFetcher类型的
            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);
        }
    
    
    • Engine类:任务创建,发起,回调,管理存活和缓存的资源,Engine类的实例对象是在GildeBuilder类中初始化的。
    • EngineJob类:实现了EngineRunnable.EngineRunnableManager接口。这个类的主要作用就是用来开启线程的,为后面的异步加载图片做准备。
    • EngineJobFactory类:是Engine类的静态内部类,里面有一个build()方法用来生成EngineJob对象,生成EngineJob对象时传入的EngineListener接口的实现是在Engine类中实现的。
    • DecodeJob类:用来对图片解码的
    • EngineRunnable类:实现Runnable接口
      看到在这个方法的参数中ResourceCallback cb参数是从GenericRequest类中传入的,GenericRequest类实现了ResourceCallback这个接口。load()方法中进行先是进行判断是否有内存缓存,如果有的话就会调用cb.onResourceReady(cached);,从缓存中加载图片。如果缓存中没有,就会创建EngineJob来开启新的线程来进行异步加载图片。
      在这个方法中在最后调用了engineJob.start(runnable);,来看一下这个EngineJob的start()方法

    EngineJob的start()方法

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

    这就会开启异步线程,来加载图片。来看一下EngineRunnable的run()方法

    EngineRunnable的run()方法

    public void run() {
            if (isCancelled) {
                return;
            }
    
            Exception exception = null;
            Resource<?> resource = null;
            try {
                //1.
                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);
            }
        }
    

    进入EngineRunnable的decode()方法

    EngineRunnable的decode()方法

    private Resource<?> decode() throws Exception {
            if (isDecodingFromCache()) {
                //这个方法会从缓存中取图片
                return decodeFromCache();
            } else {
                return decodeFromSource();
            }
        }
    private Resource<?> decodeFromSource() throws Exception {
            //decodeJob是在Engine的load()方法中创建EngineRunnable对象时传入的DecodeJob对象
            return decodeJob.decodeFromSource();
        }
    

    DecodeJob的decodeFromSource()方法

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

    先看这个DecodeJob的decodeSource()方法

    DecodeJob的 decodeSource()方法

    private Resource<T> decodeSource() throws Exception {
            Resource<T> decoded = null;
            try {
                long startTime = LogTime.getLogTime();
                //1.这个fetcher就是就是在GenericRequest类中得到的ImageVideoFetcher类型的对象并传入Engine类并之后传入DecodeJob中
                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;
        }
    

    1处调用了fetcher.loadData(priority);这个fetcher是ImageVideoFetcher类型的,来看看这个ImageVideoFetcher类的load()方法。

    ImageVideoFetcher类

    static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
            private final DataFetcher<InputStream> streamFetcher;
            private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
    
            public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
                    DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
                this.streamFetcher = streamFetcher;
                this.fileDescriptorFetcher = fileDescriptorFetcher;
            }
    
            @SuppressWarnings("resource")
            // @see ModelLoader.loadData
            @Override
            public ImageVideoWrapper loadData(Priority priority) throws Exception {
                InputStream is = null;
                if (streamFetcher != null) {
                    try {
                        //1.之前已经分析过了这个streamFetcher是HttpUrlFetcher类型
                        is = streamFetcher.loadData(priority);
                    } catch (Exception e) {
                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
                            Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
                        }
                        if (fileDescriptorFetcher == null) {
                            throw e;
                        }
                    }
                }
                ParcelFileDescriptor fileDescriptor = null;
                if (fileDescriptorFetcher != null) {
                    try {
                        fileDescriptor = fileDescriptorFetcher.loadData(priority);
                    } catch (Exception e) {
                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
                            Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
                        }
                        if (is == null) {
                            throw e;
                        }
                    }
                }
                return new ImageVideoWrapper(is, fileDescriptor);
            }
        }
    }
    

    进入HttpUrlFetcher类的load()方法看看。

    HttpUrlFetcher类的load()方法

     public InputStream loadData(Priority priority) throws Exception {
            return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
        }
    
        private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
                throws IOException {
            if (redirects >= MAXIMUM_REDIRECTS) {
                throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
            } else {
                // Comparing the URLs using .equals performs additional network I/O and is generally broken.
                // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
                try {
                    if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
                        throw new IOException("In re-direct loop");
                    }
                } catch (URISyntaxException e) {
                    // Do nothing, this is best effort.
                }
            }
            urlConnection = connectionFactory.build(url);
            for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
              urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
            }
            urlConnection.setConnectTimeout(2500);
            urlConnection.setReadTimeout(2500);
            urlConnection.setUseCaches(false);
            urlConnection.setDoInput(true);
    
            // Connect explicitly to avoid errors in decoders if connection fails.
            urlConnection.connect();
            if (isCancelled) {
                return null;
            }
            final int statusCode = urlConnection.getResponseCode();
            if (statusCode / 100 == 2) {
                return getStreamForSuccessfulRequest(urlConnection);
            } else if (statusCode / 100 == 3) {
                String redirectUrlString = urlConnection.getHeaderField("Location");
                if (TextUtils.isEmpty(redirectUrlString)) {
                    throw new IOException("Received empty or null redirect url");
                }
                URL redirectUrl = new URL(url, redirectUrlString);
                return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
            } else {
                if (statusCode == -1) {
                    throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
                }
                throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
            }
        }
    

    发现了吧,在这里面发生了网络请求。最后返回的是InputStream流。
    回到ImageVideoFetcher的loadData()方法中,发现最后将这个InputStream流包装生成了ImageVideoWrapper对象。
    ImageVideoFetcher的loadData()方法结束了,回到DecodeJob的 decodeSource()方法中,又调用了decodeFromSourceData(data);方法。并将刚刚从ImageVideoFetcher的loadData()方法中得到的ImageVideoWrapper对象传入这个decodeFromSourceData(data);方法。

    DecodeJob的decodeFromSourceData(data)方法

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

    这个方法中着重看一下decoded = loadProvider.getSourceDecoder().decode(data, width, height);这行代码。
    首先这个loadProvider之前已经分析过了,loadProvider.getSourceDecoder().最终会得到FixedLoadProvider类的构造器中传入的ImageVideoGifDrawableLoadProvider类getSourceDecoder()方法所返回的结果,最后得到的是GifBitmapWrapperResourceDecoder对象。所以最终loadProvider.getSourceDecoder().decode(data, width, height);这句代码会调用GifBitmapWrapperResourceDecoder对象的decode()方法。

    GifBitmapWrapperResourceDecoder的decode()方法

    public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
            ByteArrayPool pool = ByteArrayPool.get();
            byte[] tempBytes = pool.getBytes();
    
            GifBitmapWrapper wrapper = null;
            try {
                wrapper = decode(source, width, height, tempBytes);
            } finally {
                pool.releaseBytes(tempBytes);
            }
            return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
        }
     private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException {
            final GifBitmapWrapper result;
            if (source.getStream() != null) {
                result = decodeStream(source, width, height, bytes);
            } else {
                //对于普通的静态图的处理
                result = decodeBitmapWrapper(source, width, height);
            }
            return result;
        }
    

    GifBitmapWrapperResourceDecoder的decodeBitmapWrapper()方法

    private final ResourceDecoder<ImageVideoWrapper, Bitmap> bitmapDecoder;
    private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
            GifBitmapWrapper result = null;
    
            Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
            if (bitmapResource != null) {
                result = new GifBitmapWrapper(bitmapResource, null);
            }
    
            return result;
        }
    

    在这个GifBitmapWrapperResourceDecoder的decodeBitmapWrapper()方法中会调用ImageVideoBitmapDecoder类中的decode()方法

    ImageVideoBitmapDecoder类中的decode()方法

    public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
            private final ResourceDecoder<InputStream, Bitmap> streamDecoder;
            Resource<Bitmap> result = null;
            InputStream is = source.getStream();
            if (is != null) {
                try {
                    result = streamDecoder.decode(is, width, height);
                } catch (IOException e) {
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
                    }
                }
            }
    
            if (result == null) {
                ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
                if (fileDescriptor != null) {
                    result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
                }
            }
            return result;
        }
    

    在这个ImageVideoBitmapDecoder类中的decode()方法中会调用StreamBitmapDecoder类的decode()方法

    StreamBitmapDecoder类的decode()方法

    public Resource<Bitmap> decode(InputStream source, int width, int height) {
            private final Downsampler downsampler;
            Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
            return BitmapResource.obtain(bitmap, bitmapPool);
        }
    

    在这个StreamBitmapDecoder类的decode()方法中会调用Downsampler类的decode()方法

    Downsampler类的decode()方法

    public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
            final ByteArrayPool byteArrayPool = ByteArrayPool.get();
            final byte[] bytesForOptions = byteArrayPool.getBytes();
            final byte[] bytesForStream = byteArrayPool.getBytes();
            final BitmapFactory.Options options = getDefaultOptions();
            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);
                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);
            }
        }
    

    在这个Downsampler类的decode()方法中j进行InputStream的读取,以及对图片的加载全都在这里了,最后会返回一个Bitmap对象。
    回到StreamBitmapDecoder类的decode()方法方法中,这个方法会将Downsampler类的decode()方法返回的Bitmap对象包装成BitmapResource对象
    回到ImageVideoBitmapDecoder类中的decode()方法中,这个方法继续返回BitmapResource对象给GifBitmapWrapperResourceDecoder类中的decodeBitmapWrapper()方法。
    回到GifBitmapWrapperResourceDecoder类中的decodeBitmapWrapper(方法,在这个方法中会将返回的BitmapResource对象包装成GifBitmapWrapper对象,最后回到GifBitmapWrapperResourceDecoder类中的decode()方法,该方法将decodeBitmapWrapper()方法中返回的GifBitmapWrapper对象包装成GifBitmapWrapperResource对象
    loadProvider.getSourceDecoder().decode(data, width, height);这句代码的过程分析结束了,最后得到了GifBitmapWrapperResource()对象,这个对象对象里面包含要加载的Bitmap对象。(BitmapResource对象里面包装的是Bitmap对象,GifBitmapWrapper对象里面包装的是BitmapResource对象,GifBitmapWrapperResource对象里面包装的是GifBitmapWrapper对象)
    回到DecodeJob的decodeFromSourceData()方法中,执行完loadProvider.getSourceDecoder().decode();后返回GifBitmapWrapperResource对象到decodeSource()方法,最后回到decodeFromSource()方法中,执行transformEncodeAndTranscode()方法。

    DecodeJob的transformEncodeAndTranscode()方法

    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;
        }
    private Resource<Z> transcode(Resource<T> transformed) {
            if (transformed == null) {
                return null;
            }
            //这个transcoder指向了在Engine中创建DecodeJob对象时传入的GifBitmapWrapperDrawableTranscoder类
            return transcoder.transcode(transformed);
        }
    

    进入GifBitmapWrapperDrawableTranscoder对象的transcode(transformed)方法。

    GifBitmapWrapperDrawableTranscoder对象的transcode(transformed)方法

    public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
            private final ResourceTranscoder<Bitmap, GlideBitmapDrawable> bitmapDrawableResourceTranscoder;
            //得到GifBitmapWrapper对象
            GifBitmapWrapper gifBitmap = toTranscode.get();
            //从GifBitmapWrapper中取出Bitmap对象
            Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();
    
            final Resource<? extends GlideDrawable> result;
            //bitmapResource为null说明为Gif类型
            if (bitmapResource != null) {
                //新建GlideBitmapDrawableTranscoder对象,将Bitmap进行
                result = 
    bitmapDrawableResourceTranscoder.transcode(bitmapResource);
            } else {
                result = gifBitmap.getGifResource();
            }
            return (Resource<GlideDrawable>) result;
        }
    

    进入GlideBitmapDrawableTranscoder的transcode()方法。

    GlideBitmapDrawableTranscoder的transcode()方法

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

    在GlideBitmapDrawableTranscoder的transcode()方法中将Bitemap对象保存在GlideBitmapDrawableResource中。
    一路返回到EngineRunnable的run()方法中,EngineRunnable的run()方法
    中的1过程分析结束了,最后的到了GlideBitmapDrawableResource对象,里面保存了要展示的Bitmp。再贴一下EngineRunnable的run()方法

    EngineRunnable的run()方法

    public void run() {
            if (isCancelled) {
                return;
            }
    
            Exception exception = null;
            Resource<?> resource = null;
            try {
                //1.
                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);
            }
        }
    

    可以看到得到Resource后,调用了EngineRunnable的onLoadComplete(resource)方法。

    EngineRunnable的onLoadComplete(resource)方法

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

    这个manager指向的是EngineRunnable的构造器中传来的EngineRunnableManager参数,这个EngineRunnableManager被EngineJob实现。
    进入EngineJob类中。

    EngineJob类中的方法

    private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
    public void onResourceReady(final Resource<?> resource) {
            this.resource = resource;
            //通过Handler发送了一条消息,切换到主线程,准备进行UI的修改
            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);
            //这个ResourceCallback前面已经分析过了,GenericRequest类实现了,在for()循环中处理ResourceCallback接口
            for (ResourceCallback cb : cbs) {
                if (!isInIgnoredCallbacks(cb)) {
                    engineResource.acquire();
                    cb.onResourceReady(engineResource);
                }
            }
            engineResource.release();
        }
    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;
            }
        }
    

    处理ResourceCallback接口时,会调用GenericRequest中的实现了ResourceCallback接口的方法。
    进入GenericRequest类中。

    GenericRequest类中

    public void onResourceReady(Resource<?> resource) {
            if (resource == null) {
                onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
                        + " inside, but instead got null."));
                return;
            }
    
            Object received = resource.get();
            if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
                releaseResource(resource);
                onException(new Exception("Expected to receive an object of " + transcodeClass
                        + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
                        + " inside Resource{" + resource + "}."
                        + (received != null ? "" : " "
                            + "To indicate failure return a null Resource object, "
                            + "rather than a Resource object containing null data.")
                ));
                return;
            }
    
            if (!canSetResource()) {
                releaseResource(resource);
                // We can't set the status to complete before asking canSetResource().
                status = Status.COMPLETE;
                return;
            }
    
            onResourceReady(resource, (R) received);
        }
    private void onResourceReady(Resource<?> resource, R result) {
            boolean isFirstResource = isFirstReadyResource();
            status = Status.COMPLETE;
            this.resource = resource;
    
            if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                    isFirstResource)) {
                GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
               //调用Target来展示图片
                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);
            }
        }
    

    GlideDrawableImageViewTarget类中

    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
            if (!resource.isAnimated()) {
                float viewRatio = view.getWidth() / (float) view.getHeight();
                float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
                if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
                        && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
                    resource = new SquaringDrawable(resource, view.getWidth());
                }
            }
            super.onResourceReady(resource, animation);
            this.resource = resource;
            resource.setLoopCount(maxLoopCount);
            resource.start();
        }
     protected void setResource(GlideDrawable resource) {
            //这个view就是我们之前into()中传进来的ImageView
            view.setImageDrawable(resource);
        }
    

    最后图片就显示出来了。

    参考

    Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

    相关文章

      网友评论

          本文标题:Glide的into()过程源码分析

          本文链接:https://www.haomeiwen.com/subject/iecuoftx.html