Glide的into()過程源碼分析

和load()過程類似,最終Glide.with(context).load(url).into(imageView).的into()方法也調(diào)用的是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.
            }
        }
        //調(diào)用了重載的into()方法,在重載的into()方法中傳入的是Target對象
        return into(glide.buildImageViewTarget(view, transcodeClass));
    }

先說一下這個Target接口。

  • Target接口:繼承自LifecycleListener接口,Glide獲取資源之后資源作用的目標,是一個回調(diào)接口,在Glide做完所有的加載和處理之后返回結(jié)果。在into()過程中,Glide會一直跟蹤Target,并在圖片加載處理之后更新Target內(nèi)部的資源引用,在Target中我們可以獲得加載的圖片資源。

繼承關(guān)系
Target接口->BaseTarget抽象類->ViewTarget抽象類(11)->ImageViewTarget抽象類(該抽象類還實現(xiàn)了GlideAnimation.ViewAdapter接口)->GlideDrawableImageViewTarget實現(xiàn)類/BitmapImageViewTarget實現(xiàn)類/DrawableImageViewTarget實現(xiàn)類
11ViewTarget抽象類中還包括了一個SizeDeterminer內(nèi)部類

Target接口->BaseTarget抽象類->SimpleTarget抽象類->AppWidgetTarget實現(xiàn)類/NotificationTarget實現(xiàn)類

繼承了Target接口的SimpleTarget抽象類和ViewTarget抽象類用于自定義抽象類

自定義Target:SimpleTarget和ViewTarget

繼承自LifecycleListener接口就很眼熟吧,對吧,繼承自LifecycleListener接口后的生命周期就可以被RequestManager所監(jiān)控,被ActivityFragmentLifeCycle所回調(diào)。

看一下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);這行代碼調(diào)用了Glide類中的buildImageViewTarget()方法,在這個方法中,調(diào)用了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()方法中會根據(jù)傳入的class參數(shù)來構(gòu)建不同的Target對象,這個class參數(shù)其實基本上只有兩種情況,如果你在使用Glide加載圖片的時候調(diào)用了asBitmap()方法,那么這里就會構(gòu)建出BitmapImageViewTarget對象,否則的話構(gòu)建的都是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()的過程(對應(yīng)ViewTarget抽象類中的一系列方法),先判斷該View的Target是否有之前的Request,有的話則釋放
        Request previous = target.getRequest();

        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }
        //1.
        Request request = buildRequest(target);
       //將新生成的Request設(shè)置到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)方法又調(diào)用了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設(shè)置參數(shù)的判斷(是否使用了thumbnail()方法和sizeMultiplier()方法),如果有使用thunmnail()方法,則生成原始圖片和縮略圖的請求,并由ThumbnailRequestCoordinator對象來協(xié)調(diào)管理,使用了sizeMultiplier()方法,則同樣的處理(前者遞歸的獲得縮略圖的Request,后者不遞歸),否則就只生成原始圖片的請求,生成的請求Request是GenericRequest對象。

  • ThumbnailRequestCoordinator對象也是一個Request,用來協(xié)調(diào)管理縮略圖和原始圖片的請求。
    獲取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的過程分析結(jié)束。
接下來2過程。
requestTracker.runRequest(request);,來先看一下RequestTracker類的runRequest()方法。

RequestTracker類的runRequest()方法

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

看到了是調(diào)用了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()方法設(shè)置了大小,直接進入onSizeReady()方法
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            //2.
            onSizeReady(overrideWidth, overrideHeight);
        } else {
           //在這個方法進行一系列的計算后還是會調(diào)用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時會調(diào)用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()方法中設(shè)置的drawable,如果沒有設(shè)置fallback()方法,則會顯示error()方法中設(shè)置的Drawable,如果沒有設(shè)置error()方法,則會顯示placeHolder()方法中設(shè)置的Drawable。
設(shè)置drawable時調(diào)用Target.onLoadFailed()方法,onLoadFailed()方法是Target接口中設(shè)置的方法,在ImageViewTarget抽象類中進行了實現(xiàn),在ImageViewTarget抽象類的onLoadFailed()方法中,就會進行調(diào)用view.setImageDrawable()方法,將Drawable設(shè)置到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;
        //將上面得到的參數(shù)傳入到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));
        }
    }

上面的注釋中已經(jīng)很明白了,在上一篇GequestRequestBuilder類的分析中已經(jīng)知道loadProvider指向的是ChildLoadProvider類型。ChildLoadProvider構(gòu)造器中又傳入了FixedLoadProvider對象,F(xiàn)ixedLoadProvider對象中傳入了ImageVideoModelLoader對象等。,在上一篇文中已經(jīng)分析過了,過程中的一些初始化的過程以及實例變量的意義及來源。Glide中很早的初始化一些東西,很早初始化的這些東西又傳入到后面的方法中,這個要注意。
好滴,onSizeReady()方法中最重要的就是調(diào)用了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類:任務(wù)創(chuàng)建,發(fā)起,回調(diào),管理存活和緩存的資源,Engine類的實例對象是在GildeBuilder類中初始化的。
  • EngineJob類:實現(xiàn)了EngineRunnable.EngineRunnableManager接口。這個類的主要作用就是用來開啟線程的,為后面的異步加載圖片做準備。
  • EngineJobFactory類:是Engine類的靜態(tài)內(nèi)部類,里面有一個build()方法用來生成EngineJob對象,生成EngineJob對象時傳入的EngineListener接口的實現(xiàn)是在Engine類中實現(xiàn)的。
  • DecodeJob類:用來對圖片解碼的
  • EngineRunnable類:實現(xiàn)Runnable接口
    看到在這個方法的參數(shù)中ResourceCallback cb參數(shù)是從GenericRequest類中傳入的,GenericRequest類實現(xiàn)了ResourceCallback這個接口。load()方法中進行先是進行判斷是否有內(nèi)存緩存,如果有的話就會調(diào)用cb.onResourceReady(cached);,從緩存中加載圖片。如果緩存中沒有,就會創(chuàng)建EngineJob來開啟新的線程來進行異步加載圖片。
    在這個方法中在最后調(diào)用了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()方法中創(chuàng)建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處調(diào)用了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.之前已經(jīng)分析過了這個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());
        }
    }

發(fā)現(xiàn)了吧,在這里面發(fā)生了網(wǎng)絡(luò)請求。最后返回的是InputStream流。
回到ImageVideoFetcher的loadData()方法中,發(fā)現(xiàn)最后將這個InputStream流包裝生成了ImageVideoWrapper對象。
ImageVideoFetcher的loadData()方法結(jié)束了,回到DecodeJob的 decodeSource()方法中,又調(diào)用了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之前已經(jīng)分析過了,loadProvider.getSourceDecoder().最終會得到FixedLoadProvider類的構(gòu)造器中傳入的ImageVideoGifDrawableLoadProvider類getSourceDecoder()方法所返回的結(jié)果,最后得到的是GifBitmapWrapperResourceDecoder對象。所以最終loadProvider.getSourceDecoder().decode(data, width, height);這句代碼會調(diào)用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 {
            //對于普通的靜態(tài)圖的處理
            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()方法中會調(diào)用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()方法中會調(diào)用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()方法中會調(diào)用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()方法中,這個方法繼續(xù)返回BitmapResource對象給GifBitmapWrapperResourceDecoder類中的decodeBitmapWrapper()方法。
回到GifBitmapWrapperResourceDecoder類中的decodeBitmapWrapper(方法,在這個方法中會將返回的BitmapResource對象包裝成GifBitmapWrapper對象,最后回到GifBitmapWrapperResourceDecoder類中的decode()方法,該方法將decodeBitmapWrapper()方法中返回的GifBitmapWrapper對象包裝成GifBitmapWrapperResource對象
loadProvider.getSourceDecoder().decode(data, width, height);這句代碼的過程分析結(jié)束了,最后得到了GifBitmapWrapperResource()對象,這個對象對象里面包含要加載的Bitmap對象。(BitmapResource對象里面包裝的是Bitmap對象,GifBitmapWrapper對象里面包裝的是BitmapResource對象,GifBitmapWrapperResource對象里面包裝的是GifBitmapWrapper對象)
回到DecodeJob的decodeFromSourceData()方法中,執(zhí)行完loadProvider.getSourceDecoder().decode();后返回GifBitmapWrapperResource對象到decodeSource()方法,最后回到decodeFromSource()方法中,執(zhí)行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中創(chuàng)建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過程分析結(jié)束了,最后的到了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后,調(diào)用了EngineRunnable的onLoadComplete(resource)方法。

EngineRunnable的onLoadComplete(resource)方法

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

這個manager指向的是EngineRunnable的構(gòu)造器中傳來的EngineRunnableManager參數(shù),這個EngineRunnableManager被EngineJob實現(xiàn)。
進入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發(fā)送了一條消息,切換到主線程,準備進行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前面已經(jīng)分析過了,GenericRequest類實現(xiàn)了,在for()循環(huán)中處理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接口時,會調(diào)用GenericRequest中的實現(xiàn)了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);
           //調(diào)用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的執(zhí)行流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容