Glide源碼解析之DecodeJob

前言

DecodeJob的主要工作是從磁盤或者數(shù)據(jù)源(比如網(wǎng)絡(luò))中獲取資源,并進(jìn)行轉(zhuǎn)換和轉(zhuǎn)碼。

class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
        Runnable,
        Comparable<DecodeJob<?>>,
        Poolable {
        
    DecodeJob(DiskCacheProvider diskCacheProvider, Pools.Pool<DecodeJob<?>> pool) {
        this.diskCacheProvider = diskCacheProvider;
        this.pool = pool;
    }

    DecodeJob<R> init(
            GlideContext glideContext,
            Object model,
            EngineKey loadKey,
            Key signature,
            int width,
            int height,
            Class<?> resourceClass,
            Class<R> transcodeClass,
            Priority priority,
            DiskCacheStrategy diskCacheStrategy,
            Map<Class<?>, Transformation<?>> transformations,
            boolean isTransformationRequired,
            boolean isScaleOnlyOrNoTransform,
            boolean onlyRetrieveFromCache,
            Options options,
            Callback<R> callback,
            int order) {
        decodeHelper.init(
                glideContext,
                model,
                signature,
                width,
                height,
                diskCacheStrategy,
                resourceClass,
                transcodeClass,
                priority,
                options,
                transformations,
                isTransformationRequired,
                isScaleOnlyOrNoTransform,
                diskCacheProvider);
        this.glideContext = glideContext;
        this.signature = signature;
        this.priority = priority;
        this.loadKey = loadKey;
        this.width = width;
        this.height = height;
        this.diskCacheStrategy = diskCacheStrategy;  //在BaseRequestOptions中默認(rèn)為DiskCacheStrategy.AUTOMATIC
        this.onlyRetrieveFromCache = onlyRetrieveFromCache;
        this.options = options;
        this.callback = callback;
        this.order = order;
        this.runReason = RunReason.INITIALIZE;  //關(guān)注點(diǎn)
        this.model = model;
        return this;
    }
}

DecodeJob 實(shí)現(xiàn)了 Runnable 接口,它運(yùn)行在 EngineJob 里面的線程池里。運(yùn)行時(shí)首先會(huì)檢查是否已經(jīng)取消了執(zhí)行,如果沒有則執(zhí)行 runWrapped()。

在 runWrapped() 中首先會(huì)判斷當(dāng)前的 runReason ,由于在 init() 中被賦值為 INITIALIZE ,則獲取到的 stage 為 Stage.RESOURCE_CACHE ( Stage 表示當(dāng)前執(zhí)行到的階段)。接著根據(jù)當(dāng)前的 Stage 獲取到的 DataFetcherGenerator 為 ResourceCacheGenerator,它用于從磁盤緩存中獲取經(jīng)過轉(zhuǎn)化后的資源。不熟悉這個(gè)類的可以看下 Glide源碼解析之ResourceCacheGenerator

    @Override
    public void run() {
        DataFetcher<?> localFetcher = currentFetcher;
        try {
            if (isCancelled) {      
                notifyFailed();
                return;
            }
            runWrapped();
        } catch (CallbackException e) {
            throw e;
        } catch (Throwable t) {
            if (stage != Stage.ENCODE) {
                throwables.add(t);
                notifyFailed();
            }
            if (!isCancelled) {
                throw t;
            }
            throw t;
        } finally {
            if (localFetcher != null) {
                localFetcher.cleanup();
            }
        }
    }
    
    private void runWrapped() {
        runWrappedCount++;
        switch (runReason) {    //在 init()中賦值為 INITIALIZE
            case INITIALIZE:        
                stage = getNextStage(Stage.INITIALIZE);
                currentGenerator = getNextGenerator();
                runGenerators();
                break;
            case SWITCH_TO_SOURCE_SERVICE:
                runGenerators();
                break;
            case DECODE_DATA:
                decodeFromRetrievedData();
                break;
            default:
                throw new IllegalStateException("Unrecognized run reason: " + runReason);
        }
    }
    
    private Stage getNextStage(Stage current) {
        switch (current) {
            case INITIALIZE:
                return diskCacheStrategy.decodeCachedResource() //默認(rèn)為true
                        ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
            case RESOURCE_CACHE:
                return diskCacheStrategy.decodeCachedData() //默認(rèn)為true
                        ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
            case DATA_CACHE:
                return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
            case SOURCE:
            case FINISHED:
                return Stage.FINISHED;
            default:
                throw new IllegalArgumentException("Unrecognized stage: " + current);
        }
    }
    
    private DataFetcherGenerator getNextGenerator() {
        switch (stage) {
            case RESOURCE_CACHE:
                return new ResourceCacheGenerator(decodeHelper, this);
            case DATA_CACHE:
                return new DataCacheGenerator(decodeHelper, this);
            case SOURCE:
                return new SourceGenerator(decodeHelper, this);
            case FINISHED:
                return null;
            default:
                throw new IllegalStateException("Unrecognized stage: " + stage);
        }
    }

加載數(shù)據(jù)

獲取到 DataFetcherGenerator 后就開始將獲取數(shù)據(jù)的操作交給它的 startNext() 來執(zhí)行,這里我們以 ResourceCacheGenerator 成功獲取為例,則 isStarted 會(huì)被賦值為 true ,不用進(jìn)入循環(huán)。最終獲取的數(shù)據(jù)會(huì)通過 DecodeJob 實(shí)現(xiàn)的 FetcherReadyCallback 的 onDataFetcherReady() 回調(diào)。

如果 ResourceCacheGenerator 沒有獲取到數(shù)據(jù),由上可知?jiǎng)t依次會(huì)交給 DataCacheGenerator (原數(shù)據(jù)的磁盤緩存) 和 SourceGenerator (從數(shù)據(jù)源加載,比如網(wǎng)絡(luò),不熟悉的可以看下 Glide源碼解析之SourceGenerator)

    private void runGenerators() {
        boolean isStarted = false;
        while (!isCancelled && currentGenerator != null
                && !(isStarted = currentGenerator.startNext())) {
            stage = getNextStage(stage);
            currentGenerator = getNextGenerator();

            if (stage == Stage.SOURCE) {
                reschedule();
                return;
            }
        }
        
        if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
            notifyFailed();
        }

    }

加載數(shù)據(jù)完成

在 ResourceCacheGenerator 加載數(shù)據(jù)成功后則通過 onDataFetcherReady() 回調(diào)給 DecodeJob ,由于 ResourceCacheGenerator 并沒有切換線程去獲取資源,所以會(huì)執(zhí)行到 decodeFromRetrievedData() 去進(jìn)行解碼。經(jīng)過一系列的調(diào)用,最終會(huì)將解碼的操作交給 LoadPath 去執(zhí)行。

    //ResourceCacheGenerator
    @Override
    public void onDataReady(Object data) {
        cb.onDataFetcherReady(sourceKey, data/*ByteBuffer*/, loadData.fetcher/*ByteBufferFetcher*/, DataSource.RESOURCE_DISK_CACHE,
                currentKey);
    }
    
    //DecodeJob
    @Override
    public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
                                   DataSource dataSource, Key attemptedKey) {
        this.currentSourceKey = sourceKey;
        this.currentData = data;
        this.currentFetcher = fetcher;
        this.currentDataSource = dataSource;
        this.currentAttemptingKey = attemptedKey;
        if (Thread.currentThread() != currentThread) {
            runReason = RunReason.DECODE_DATA;
            callback.reschedule(this);
        } else {
            try {
                decodeFromRetrievedData();  // 執(zhí)行點(diǎn)  
            } finally {
                GlideTrace.endSection();
            }
        }
    }
    
    private void decodeFromRetrievedData() {
        Resource<R> resource = null;
        try {
            resource = decodeFromData(currentFetcher, currentData, currentDataSource);     // 執(zhí)行點(diǎn)  
        } catch (GlideException e) {
            e.setLoggingDetails(currentAttemptingKey, currentDataSource);
            throwables.add(e);
        }
        if (resource != null) {
            notifyEncodeAndRelease(resource, currentDataSource);
        } else {
            runGenerators();
        }
    }
    
    private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
                                              DataSource dataSource) throws GlideException {
        try {
            if (data == null) {
                return null;
            }
            Resource<R> result = decodeFromFetcher(data, dataSource);   // 執(zhí)行點(diǎn)  
            return result;
        } finally {
            fetcher.cleanup();
        }
    }
    
    private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
            throws GlideException {
        LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());  // 執(zhí)行點(diǎn)
        return runLoadPath(data, dataSource, path);
    }
    
    private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
                                                         LoadPath<Data, ResourceType, R> path) throws GlideException {
        Options options = getOptionsWithHardwareConfig(dataSource);
        DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);   // ByteBufferRewinder
        try {
            return path.load(
                    rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));  // 執(zhí)行點(diǎn)
        } finally {
            rewinder.cleanup();
        }
    }

開始解碼

會(huì)遍歷 decodePaths 來尋找哪個(gè) DecodePath 是能完成解碼工作的,而具體解碼由分為三步,第一步為解碼資源,第二步為解碼之后的工作(實(shí)際為對(duì)資源進(jìn)行緩存),第三步為轉(zhuǎn)碼,即是將獲取到的資源類型轉(zhuǎn)為另一種資源類型。

    //LoadPath
    public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
                                    int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
        List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
        try {
            return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);      // 執(zhí)行點(diǎn)
        } finally {
            listPool.release(throwables);
        }
    }
    
    private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
                                                      @NonNull Options options,
                                                      int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
                                                      List<Throwable> exceptions) throws GlideException {
        Resource<Transcode> result = null;
        for (int i = 0, size = decodePaths.size(); i < size; i++) {
            DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
            try {
                result = path.decode(rewinder, width, height, options, decodeCallback);  // 執(zhí)行點(diǎn)
            } catch (GlideException e) {
                exceptions.add(e);
            }
            if (result != null) {
                break;
            }
        }

        if (result == null) {
            throw new GlideException(failureMessage, new ArrayList<>(exceptions));
        }

        return result;
    }

    //DecodePath
    public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
                                      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
        Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
        Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
        return transcoder.transcode(transformed, options);
    }
    

解碼資源

當(dāng)資源類型是 ByteBuffer 的時(shí)候,對(duì)應(yīng)的 DataRewinder 是 ByteBufferRewinder ,ResourceDecoder 是 ByteBufferBitmapDecoder ,則最終的解碼操作將由 ByteBufferBitmapDecoder 來完成。

    @NonNull
    private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
                                                  int height, @NonNull Options options) throws GlideException {
        List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
        try {
            return decodeResourceWithList(rewinder, width, height, options, exceptions);   //執(zhí)行點(diǎn)
        } finally {
            listPool.release(exceptions);
        }
    }
    
    @NonNull
    private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder /*ByteBufferRewinder*/, int width,
                                                          int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
        Resource<ResourceType> result = null;
        for (int i = 0, size = decoders.size(); i < size; i++) {
            ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
            try {
                DataType data = rewinder.rewindAndGet();
                if (decoder.handles(data, options)) {
                    //ByteBufferBitmapDecoder
                    data = rewinder.rewindAndGet();
                    result = decoder.decode(data, width, height, options);  //執(zhí)行點(diǎn)
                }
            } catch (IOException | RuntimeException | OutOfMemoryError e) {
                exceptions.add(e);
            }

            if (result != null) {
                break;
            }
        }

        if (result == null) {
            throw new GlideException(failureMessage, new ArrayList<>(exceptions));
        }
        return result;
    }

首先會(huì)將 ByteBuffer 轉(zhuǎn)化為 InputStream ,然后再交給 Downsampler來解碼。

    public class ByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> {
      private final Downsampler downsampler;
    
      public ByteBufferBitmapDecoder(Downsampler downsampler) {
        this.downsampler = downsampler;
      }
    
      @Override
      public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
        return downsampler.handles(source);
      }
    
      @Override
      public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width, int height,
          @NonNull Options options)
          throws IOException {
        InputStream is = ByteBufferUtil.toStream(source);
        return downsampler.decode(is, width, height, options);
      }
    }
    
    //Downsampler
    public boolean handles(@SuppressWarnings("unused") ByteBuffer byteBuffer) {
        return true;
    }
    
    //ByteBufferUtil
    public static InputStream toStream(@NonNull ByteBuffer buffer) {
        return new ByteBufferStream(buffer);
    }

在解碼操作里首先會(huì)根據(jù) Bitmap 的寬高和 ImageView 的寬高來計(jì)算出縮放值,然后從 BitmapPool 獲取一個(gè)合適寬高的 Bitmap 交給 BitmapFactory 去進(jìn)行最終的解碼操作,最后再判斷是否需要對(duì) Bitmap 進(jìn)行旋轉(zhuǎn)。

獲取到 Bitmap 后將它包裝進(jìn) BitmapResource 里返回,到此解碼資源的工作就完成了。

    //Downsampler
    public Resource<Bitmap> decode(InputStream is, int outWidth, int outHeight,
                                   Options options) throws IOException {
        return decode(is, outWidth, outHeight, options, EMPTY_CALLBACKS);
    }
    
    public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
                                   Options options, DecodeCallbacks callbacks) throws IOException {
        //省略取值代碼

        try {
            Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
                    downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth,
                    requestedHeight, fixBitmapToRequestedDimensions, callbacks);
            return BitmapResource.obtain(result, bitmapPool);
        } finally {
            releaseOptions(bitmapFactoryOptions);
            byteArrayPool.put(bytesForOptions);
        }
    }
    
    private Bitmap decodeFromWrappedStreams(InputStream is,
                                            BitmapFactory.Options options, DownsampleStrategy downsampleStrategy,
                                            DecodeFormat decodeFormat, boolean isHardwareConfigAllowed, int requestedWidth,
                                            int requestedHeight, boolean fixBitmapToRequestedDimensions,
                                            DecodeCallbacks callbacks) throws IOException {
        
        //省略代碼

        //計(jì)算圖片的縮放值,設(shè)置給 options
        calculateScaling(
                imageType,
                is,
                callbacks,
                bitmapPool,
                downsampleStrategy,
                degreesToRotate,
                sourceWidth,
                sourceHeight,
                targetWidth,
                targetHeight,
                options);
                
        //計(jì)算配置
        calculateConfig(
                is,
                decodeFormat,
                isHardwareConfigAllowed,
                isExifOrientationRequired,
                options,
                targetWidth,
                targetHeight);

        boolean isKitKatOrGreater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        if ((options.inSampleSize == 1 || isKitKatOrGreater) && shouldUsePool(imageType)) {
            //不用縮放或者系統(tǒng)版本大于19,而且可以使用 BitmapPool
            
            int expectedWidth;
            int expectedHeight;
            if (sourceWidth >= 0 && sourceHeight >= 0
                    && fixBitmapToRequestedDimensions && isKitKatOrGreater) {
                expectedWidth = targetWidth;
                expectedHeight = targetHeight;
            } else {
                float densityMultiplier = isScaling(options)
                        ? (float) options.inTargetDensity / options.inDensity : 1f;
                int sampleSize = options.inSampleSize;
                int downsampledWidth = (int) Math.ceil(sourceWidth / (float) sampleSize);
                int downsampledHeight = (int) Math.ceil(sourceHeight / (float) sampleSize);
                expectedWidth = Math.round(downsampledWidth * densityMultiplier);
                expectedHeight = Math.round(downsampledHeight * densityMultiplier);
            }

            if (expectedWidth > 0 && expectedHeight > 0) {
                setInBitmap(options, bitmapPool, expectedWidth, expectedHeight);    //去 BitmapPool 中獲取期望寬高的 Bitmap (設(shè)置給 options.inBitmap)
            }
        }
        
        Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool);    //執(zhí)行點(diǎn)
        callbacks.onDecodeComplete(bitmapPool, downsampled);    //空實(shí)現(xiàn)

        Bitmap rotated = null;
        if (downsampled != null) {
            // 在上面 calculateScaling() 會(huì)修改 inDensity,這里設(shè)置回來
            downsampled.setDensity(displayMetrics.densityDpi);

            rotated = TransformationUtils.rotateImageExif(bitmapPool, downsampled, orientation);  //旋轉(zhuǎn)圖片
            
            if (!downsampled.equals(rotated)) {
                //如果旋轉(zhuǎn)了,則緩存旋轉(zhuǎn)后的 Bitmap 。如果沒旋轉(zhuǎn)則還是原來的 Bitmap
                bitmapPool.put(downsampled);
            }
        }

        return rotated;
    }
    
    private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options,
                                       DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException {
        if (options.inJustDecodeBounds) {
            is.mark(MARK_POSITION);
        } else {
            callbacks.onObtainBounds();
        }
       
        int sourceWidth = options.outWidth;
        int sourceHeight = options.outHeight;
        String outMimeType = options.outMimeType;
        final Bitmap result;
        TransformationUtils.getBitmapDrawableLock().lock();
        try {
            result = BitmapFactory.decodeStream(is, null, options);  //最終還是靠 BitmapFactory 來生成 Bitmap 的
        } catch (IllegalArgumentException e) {
            IOException bitmapAssertionException =
                    newIoExceptionForInBitmapAssertion(e, sourceWidth, sourceHeight, outMimeType, options);
            throw bitmapAssertionException;
        } finally {
            TransformationUtils.getBitmapDrawableLock().unlock();
        }

        return result;
    }

編碼資源

解碼資源完成后接著就輪到編碼資源了,由 DecodeCallback (接口) 去執(zhí)行,在 DecodeJob 的 runLoadPath() 中給callback 賦的值是 DecodeCallback (實(shí)現(xiàn)類),而它將具體的編碼操作又交回給了 DecodeJob 的 onResourceDecoded()去執(zhí)行。

首先會(huì)判斷資源是否可以編碼,由上可知資源類型為 Bitmap ,是可以編碼的。接著判斷是否可以進(jìn)行緩存,由于這里是從 ResourceCacheGenerator 獲取數(shù)據(jù)的,本來就是從緩存中取得數(shù)據(jù),所以不再需要進(jìn)行緩存,最終會(huì)將源數(shù)據(jù)返回。

如果是需要緩存的則會(huì)交給 DeferredEncodeManager 進(jìn)行磁盤緩存,如果對(duì)磁盤緩存不熟悉的可以看下 Glide源碼解析之DiskCache

    //DecodePath
    public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
                                      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
        Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
        Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);    //執(zhí)行點(diǎn)
        return transcoder.transcode(transformed, options);
    }
    
    private final class DecodeCallback<Z> implements DecodePath.DecodeCallback<Z> {

        private final DataSource dataSource;

        @Synthetic
        DecodeCallback(DataSource dataSource) {
            this.dataSource = dataSource;
        }

        @NonNull
        @Override
        public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
            return DecodeJob.this.onResourceDecoded(dataSource, decoded);
        }
    }
    
    <Z> Resource<Z> onResourceDecoded(DataSource dataSource,
                                      @NonNull Resource<Z> decoded) {
        Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
        Transformation<Z> appliedTransformation = null;
        Resource<Z> transformed = decoded;
        
        // ResourceCacheGenerator 回調(diào)給 DecodeJob 的就是 DataSource.RESOURCE_DISK_CACHE
        if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
            appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
            transformed = appliedTransformation.transform(glideContext, decoded, width, height);
        }
        
        if (!decoded.equals(transformed)) {
            decoded.recycle();
        }

        final EncodeStrategy encodeStrategy;
        final ResourceEncoder<Z> encoder;
        if (decodeHelper.isResourceEncoderAvailable(transformed)) {
            encoder = decodeHelper.getResultEncoder(transformed);   // BitmapEncoder
            encodeStrategy = encoder.getEncodeStrategy(options);    // EncodeStrategy.TRANSFORMED
        } else {
            encoder = null;
            encodeStrategy = EncodeStrategy.NONE;
        }

        Resource<Z> result = transformed;
        
        //從 ResourceCacheGenerator 獲取數(shù)據(jù)用的是 sourceKey ,所以這里是 false。
        //因?yàn)槲覀儽緛砭褪菑木彺嬷腥〉臄?shù)據(jù),所以并不需要再次緩存。
        boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);   
        
        if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,
                encodeStrategy)) {
            
            //這里面是生成緩存的 Key ,并將緩存的操作交給 deferredEncodeManager 去執(zhí)行
            if (encoder == null) {
                throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
            }
            final Key key;
            switch (encodeStrategy) {
                case SOURCE:
                    key = new DataCacheKey(currentSourceKey, signature);    //代表緩存的是源數(shù)據(jù)
                    break;  
                case TRANSFORMED:
                    key =
                            new ResourceCacheKey(
                                    decodeHelper.getArrayPool(),
                                    currentSourceKey,
                                    signature,
                                    width,
                                    height,
                                    appliedTransformation,
                                    resourceSubClass,
                                    options);   //代表緩存的是經(jīng)過轉(zhuǎn)化的數(shù)據(jù)
                    break;
                default:
                    throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
            }

            LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
            deferredEncodeManager.init(key, encoder, lockedResult);     
            result = lockedResult;
        }
        return result;
    }
    
    //DeferredEncodeManager
    void encode(DiskCacheProvider diskCacheProvider, Options options) {
        try {
            //進(jìn)行磁盤緩存
            diskCacheProvider.getDiskCache().put(key,
                    new DataCacheWriter<>(encoder, toEncode, options));
        } finally {
            toEncode.unlock();
        }
    }

轉(zhuǎn)碼

將 Resource<Bitmap> 傳進(jìn) LazyBitmapDrawableResource ,而 LazyBitmapDrawableResource 有一個(gè) get() 將 Resource<Bitmap> 轉(zhuǎn)化為 BitmapDrawable 。到此數(shù)據(jù)的獲取過程就結(jié)束了。

    //BitmapDrawableTranscoder
    public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
      @NonNull Options options) {
        return LazyBitmapDrawableResource.obtain(resources, toTranscode);
    }
    
    //LazyBitmapDrawableResource
    public static Resource<BitmapDrawable> obtain(
      @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
        if (bitmapResource == null) {
            return null;
        }
        return new LazyBitmapDrawableResource(resources, bitmapResource);
    }
    
    public BitmapDrawable get() {
        return new BitmapDrawable(resources /*這是 Android 里面的 Resource */, bitmapResource.get());
    }
    

處理數(shù)據(jù)

讓我們回到 DecodeJob 一開始獲取數(shù)據(jù)的時(shí)候,在獲取到數(shù)據(jù)之后通過回調(diào)將數(shù)據(jù)傳給 EngineJob 。接著如果需要緩存的則調(diào)用 deferredEncodeManager 去執(zhí)行,最后釋放資源。到此 DecodeJob 的使命就全部完成了。

    //DecodeJob
    private void decodeFromRetrievedData() {
        Resource<R> resource = null;
        try {
            resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
            e.setLoggingDetails(currentAttemptingKey, currentDataSource);
            throwables.add(e);
        }
        if (resource != null) {
            notifyEncodeAndRelease(resource, currentDataSource);   //執(zhí)行點(diǎn) 
        } else {
            runGenerators();
        }
    }
    
    private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
        if (resource instanceof Initializable) {
            ((Initializable) resource).initialize();
        }

        Resource<R> result = resource;
        LockedResource<R> lockedResource = null;
        if (deferredEncodeManager.hasResourceToEncode()) {
            lockedResource = LockedResource.obtain(resource);
            result = lockedResource;
        }

        notifyComplete(result, dataSource);     //執(zhí)行點(diǎn)

        stage = Stage.ENCODE;
        try {
            if (deferredEncodeManager.hasResourceToEncode()) {
                //上面說過 deferredEncodeManager 是用來調(diào)用磁盤緩存的,就是在這里調(diào)用
                deferredEncodeManager.encode(diskCacheProvider, options);
            }
        } finally {
            if (lockedResource != null) {
                lockedResource.unlock();
            }
        }
        
        //釋放資源
        onEncodeComplete();
    }
   
    private void notifyComplete(Resource<R> resource, DataSource dataSource) {
        callback.onResourceReady(resource, dataSource);
    }
    
    //EngineJob    
    public void onResourceReady(Resource<R> resource, DataSource dataSource) {
        synchronized (this) {
            this.resource = resource;
            this.dataSource = dataSource;
        }
        notifyCallbacksOfResult();
    } 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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