Glide源碼解讀(二)

前面文章分析到buildRequest方法,現在繼續看

buildRequest方法,調用了buildRequestRecursive方法

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

buildRequestRecursive方法,前面兩個if判斷都是判斷是否設置了縮略圖需要,調用了thumbnai兩個方法走兩個if,

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()");
        }
        // Recursive case: contains a potentially recursive thumbnail request builder.
        if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
            thumbnailRequestBuilder.animationFactory = animationFactory;
        }

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

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

        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
        isThumbnailBuilt = true;
        // Recursively generate thumbnail requests.
        Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
        coordinator.setRequests(fullRequest, thumbRequest);
        return coordinator;
    } else if (thumbSizeMultiplier != null) {
        // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
        Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
        coordinator.setRequests(fullRequest, thumbnailRequest);
        return coordinator;
    } else {
        // Base case: no thumbnail.
        return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
    }
}

不過最終都會調用obtainRequest方法,該方法直接調用GenericRequest類的obtain方法

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,
            requestListener,
            requestCoordinator,
            glide.getEngine(),
            transformation,
            transcodeClass,
            isCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
}

GenericRequest 的 obtain方法,該方法從REQUEST_POOL隊列裏面拿請求,如果沒有則生成

public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
        ...省略參數) {
    @SuppressWarnings("unchecked")
	//從隊列裏面拿出一個請求
    GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
	//沒有則直接生成一個
    if (request == null) {
        request = new GenericRequest<A, T, Z, R>();
    }
	//省略一系列參數
    request.init(...);
    return request;
}

調用了GenericRequest的init方法,該方法就是直接把參數賦值到對象裏面

繼續看into方法。構建request後, 把request丟進了requestTracker執行

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裏面的request。清楚和回收
    Request previous = target.getRequest();

    if (previous != null) {
        previous.clear();
        requestTracker.removeRequest(previous);
        previous.recycle();
    }
	//構建requeset
    Request request = buildRequest(target);
    target.setRequest(request);
    lifecycle.addListener(target);
    requestTracker.runRequest(request);

    return target;
}

RequestTracker 的runRequest方法,把request放入requests集合,如果已經是暫停狀態了,則放入pendingRequests集合,否則執行begin方法。至於什麼時候是暫停狀態,看什麼時候調用了pauseRequests方法。

 public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
		//調用request的begin方法
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }

Request的begin方法。如果前面調用了thumbnai方法,則會走onSizeReady,否則走else語句,我們沒設置,看getSize方法

public void begin() {
    startTime = LogTime.getLogTime();
    if (model == null) {
        onException(null);
        return;
    }
	//設置狀態
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }

    if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
}

getSize在ViewTarget裏面實現,邏輯也很清晰,去獲取控件的寬高,如果獲取不到,則利用ViewTreeObserver的監聽去獲取, 而我們在Activity的onCreate方法裏面如果想獲取控件的寬高,一般也會如此。最後獲取到寬高後都會調用Request的onSizeReady方法

public void getSize(SizeReadyCallback cb) {
        int currentWidth = getViewWidthOrParam();
        int currentHeight = getViewHeightOrParam();
        if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
            cb.onSizeReady(currentWidth, currentHeight);
        } else {
            // We want to notify callbacks in the order they were added and we only expect one or two callbacks to
            // be added a time, so a List is a reasonable choice.
            if (!cbs.contains(cb)) {
                cbs.add(cb);
            }
            if (layoutListener == null) {
                final ViewTreeObserver observer = view.getViewTreeObserver();
                layoutListener = new SizeDeterminerLayoutListener(this);
                observer.addOnPreDrawListener(layoutListener);
            }
        }
    }

GenericRequest的onSizeReady方法,寬高是我們前面獲取到的,sizeMultiplier默認是1,關鍵代碼是嗲用了engine的load方法,這個方法好像纔是去真正加載資源的地方。

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

    ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
    final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

    if (dataFetcher == null) {
        onException(new Exception("Got null fetcher from model loader"));
        return;
    }
    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));
    }
}

Engine的load方法,生成了一個DecodeJob對象放入EngineJob對象,並放入LoadStatus裏面,返回。

//省略參數
public <T, Z, R> LoadStatus load(...) {
    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());
	//1 從緩存中獲取
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
	//獲取到,回調。從緩存中獲取到後放入activeResources集合
    if (cached != null) {
        cb.onResourceReady(cached);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }
	//2 從activeResources集合中獲取
    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;
    }
	//緩存和activeResources中都沒有,根據key查詢是否已經生成了EnginJob。
    EngineJob current = jobs.get(key);
    if (current != null) {
        current.addCallback(cb);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }

    EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
    DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
            transcoder, diskCacheProvider, diskCacheStrategy, priority);
    EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
	//3 把runnable提交到線程池執行
    engineJob.start(runnable);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
}

先看註釋1 ,從緩存中加載,通過用remove方法獲取,那麼緩存只緩存一次,從緩存中獲取後,把緩存中的又放入activeResources集合。調用acquire方法只是統計它的調用次數。當內存不夠時根據調用頻率釋放內存。

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
        cached.acquire();
        activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
    }
    return cached;
}

@SuppressWarnings("unchecked")
private EngineResource<?> getEngineResourceFromCache(Key key) {
    Resource<?> cached = cache.remove(key);

    final EngineResource result;
    if (cached == null) {
        result = null;
    } else if (cached instanceof EngineResource) {
        // Save an object allocation if we've cached an EngineResource (the typical case).
        result = (EngineResource) cached;
    } else {
        result = new EngineResource(cached, true /*isCacheable*/);
    }
    return result;
}

註釋2 ,從activeResources集合中獲取,獲取到,更新調用頻率。獲取不到,則刪除key.因爲value用的弱引用。可能被回收了,這樣key也無效了。這樣看它真是的緩存就是activeResources集合了。

private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }

    EngineResource<?> active = null;
    WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
    if (activeRef != null) {
        active = activeRef.get();
        if (active != null) {
            active.acquire();
        } else {
            activeResources.remove(key);
        }
    }

    return active;
}

註釋3,提交到線程池。那就看run方法了。

//執行線程池
public void start(EngineRunnable engineRunnable) {
    this.engineRunnable = engineRunnable;
    future = diskCacheService.submit(engineRunnable);
}

EngineRunnable實現了Runnable接口,因此直接看run方法,裏面主要調用了decode()方法,然後再回調。

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

    Exception exception = null;
    Resource<?> resource = null;
    try {
		
        resource = decode();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Exception decoding", e);
        }
        exception = e;
    }

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

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

看decode方法,判斷是否從緩存

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

由於我們是沒加載過,因此走else分支的decodeFromSouce方法

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

調用DecodeJob的decodeFromSource方法

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

調用了fetcher方法的loadData方法,由於前面我們知道這個類是個HttpUrlFetcher類,應該去該類查看loadData方法

private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        final A data = fetcher.loadData(priority);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Fetched data", startTime);
        }
        if (isCancelled) {
            return null;
        }
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}

HttpUrlFetcher的loadData方法。內部調用了loadDataWithRedirects方法,裏面有我們熟悉的HttpURLConnection 網絡請求,看了這麼久終於看到網絡請求的代碼了,該方法如果請求成功返回InputStream,如果失敗還會重試4次。

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

    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl) throws IOException {
		//如果次數大於5次,返回錯誤
        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);
        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) {
            stream = urlConnection.getInputStream();
            return stream;
        } 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);
        } else {
            if (statusCode == -1) {
                throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
            }
            throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
        }
    }

繼續看該方法, 服務器返回的數據在InputStream裏面,然後在調用decodeFromSourceData,去解析InputStream。

private Resource<T> decodeSource() throws Exception {
        Resource<T> decoded = null;
        try {
            long startTime = LogTime.getLogTime();
            final A data = fetcher.loadData(priority);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Fetched data", startTime);
            }
            if (isCancelled) {
                return null;
            }
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }

decodeFromSourceData方法,調用了decode方法去解析。當我們點進decode方法時,發現又是一個接口,還帶兩泛型。也一樣要知道它的實現類是哪個,才能知道它最終的實現方法。查找實現類和我們前面的查找fetcher類的方式一樣。這裏我們就不再和前面一樣去貼代碼,知道這裏最終調用的實現類是StreamBitmapDecoder的decode方法,

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

StreamBitmapDecoder,這個類把解析工作委託給Downsampler類了

public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
    ...

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

   ...
}

decode方法裏面調用了downsampleWithSize方法,而downsampleWithSize方法會調用decodeStream方法,decodeStream裏面調用我們熟悉的BitmapFactory.decodeStream方法。當然它裏面對流做了優化處理。具體細節可詳細參考decode方法。這裏我們只是查看其大概流程。細節不作深入研究。

public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
  		...
        final Bitmap downsampled =
                downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,
                        decodeFormat);
        ...
        Bitmap rotated = null;
		//判斷是否需要旋轉
        if (downsampled != null) {
            rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);

            if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
                downsampled.recycle();
            }
        }

        return rotated;
    ...
}

最終也是調用了BitmapFactory.decodeStream方法

private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
        BitmapFactory.Options options) {
     ...
    final Bitmap result = BitmapFactory.decodeStream(is, null, options);
    ...
    return result;
}


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

當這個方法執行後,終於拿到我們需要的Bitmap對象了。繼續回到Decode的decodeFromSource方法。

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


private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
        long startTime = LogTime.getLogTime();
		//如果需要對bitmap進行處理,則處理
        Resource<T> transformed = transform(decoded);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transformed resource from source", startTime);
        }
		//寫入文件緩存
        writeTransformedToCache(transformed);

        startTime = LogTime.getLogTime();
		//把Bitmap轉換爲drawable
        Resource<Z> result = transcode(transformed);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transcoded transformed from source", startTime);
        }
        return result;
    }

Glide裏面,其中decodedClass是個GifBitmapWrapper類型,transcodedClass是個GlideDrawable類型

 <Z, R> ResourceTranscoder<Z, R> buildTranscoder(Class<Z> decodedClass, Class<R> transcodedClass) {
        return transcoderRegistry.get(decodedClass, transcodedClass);
    }

在Glide的構造器裏面,已經把對應的ResourceTranscoder實現類提前放入map集合中,根據前面兩個參數的Class類型獲取到後面對應的類,這裏我們獲取到的是GifBitmapWrapperDrawableTranscoder類,

 Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
   	...
   
    transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
            new GifBitmapWrapperDrawableTranscoder(
                    new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));
   ...
}

由前面我們分析到transcode方法時,調用的是GifBitmapWrapperDrawableTranscoder類的transcode方法。

private Resource<Z> transcode(Resource<T> transformed) {
    if (transformed == null) {
        return null;
    }
    return transcoder.transcode(transformed);
}

因此我們看GifBitmapWrapperDrawableTranscoder 的transcode方法

@Override
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
    GifBitmapWrapper gifBitmap = toTranscode.get();
    Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();

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

實際還是調用了bitmapDrawableResourceTranscoder的transcode方法,

繼續查看

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

返回一個GlideBitmapDrawableResource對象。

最終會調用transcode方法,調用transcoder.transcode();而這個transcoder哪裏被賦值的呢?

private Resource<Z> transcode(Resource<T> transformed) {
    if (transformed == null) {
        return null;
    }
    return transcoder.transcode(transformed);
}

在GenericRequest的onSizeReady方法裏,可以看到是從loadProvider裏面獲取到的這個transcoder對象。

@Override
public void onSizeReady(int width, int height) {
    ...
	//從loadProvider對象裏面獲取的transcoder對象
    ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
    ...
    loadedFromMemoryCache = true;
    loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
            priority, isMemoryCacheable, diskCacheStrategy, this);
    loadedFromMemoryCache = resource != null;
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
}

如果load到資源,則會調用回調ResourceCallback 的onResourceReady方法,也就是GenericRequest的onResourceReady方法

public <T, Z, R> LoadStatus load(...) {
        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;
        }

       ...
    }


 public void onResourceReady(Resource<?> resource) {
       ...
		//調用重載方法
        onResourceReady(resource, (R) received);
    }

重載方法裏面調用了target的onResourceReady方法

    private void onResourceReady(Resource<?> resource, R result) {
        if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                isFirstReadyResource())) {
            GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstReadyResource());
			//調用target方法的onResourceReady方法
            target.onResourceReady(result, animation);
        }
        status = Status.COMPLETE;
        this.resource = resource;
        notifyLoadSuccess();

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
                    + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
        }
    }

由前面可知,我們的這個target是個GlideDrawableImageViewTarget對象,因此看onResourceReady方法

public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> {
    
    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
        super.onResourceReady(resource, animation);
        this.resource = resource;
        resource.setLoopCount(maxLoopCount);
        resource.start();
    }
}

調用了父類的onResourceReady方法,父類會調用子類的setResource方法,因此我們看setResource方法
就是最終在我們傳入的ImageView設置drawable

protected void setResource(GlideDrawable resource) {
    view.setImageDrawable(resource);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章