Glide原理之执行流程分析

作者: Ihesong | 来源:发表于2018-06-24 17:20 被阅读36次

    Glide是一个优秀的图片加载库,它有如下优点:

    1. Glide可以监听Activity的生命周期管理,更加合理的管理图片的加载和释放。
    2. 加载质量,Picasso默认采用的ARGB-8888, Glide默认采用的是RGB-565,内存占用会减小一半。
    3. Glide可以加载Gif图。
    4. 缓存策略和加载速度。Picasso缓存的是全尺寸,而Glide的缓存的图片和ImageView的尺寸相同。Glide的这个特点,让加载显得特别的快,而Picasso则因为需要在显示之前重新调整大小而导致一些延迟。
    5. Glide可以通过自定义GlideMoudle来完成特殊的加载需求,例如加载加密的图片等。

    这里简单分析一下Glide是怎么样的一个加载流程。

    Glide生命周期监听

    Glide提供了众多with方法,可以传入Activity, Context, Fragment, FragmentActivity。然后根据不同情况会作不同的处理。

    1. 创建RequestManagerFragment对象并添加到FragmentManager中负责监听生命周期变化,创建RequestManager对象。
    2. 创建SupportRequestManagerFragment对象并添加到FragmentManager中负责监听生命周期变化,创建RequestManager对象。
    3. 普通Context情况,只是创建RequestManager对象。
      因此针对是Activity,Fragment的情况,可以监听生命周期,启动和暂停图片的加载等等,更加智能,这个比Picasso要更有优势。

    Glide初始化

    也就是Glide.get(Context context)方法,负责解析AndroidManifest清单文件中定义的GlideMoudle,并调用它的applyOptions和registerComponents接口方法,通常我们自定义的GlideMoudle就是要实现这两个接口方法。

    /**
     * Get the singleton.
     *
     * @return the singleton
     */
    public static Glide get(Context context) {
        if (glide == null) {
            synchronized (Glide.class) {
                if (glide == null) {
                    Context applicationContext = context.getApplicationContext();
                    List<GlideModule> modules = new ManifestParser(applicationContext).parse();
    
                    GlideBuilder builder = new GlideBuilder(applicationContext);
                    for (GlideModule module : modules) {
                        module.applyOptions(applicationContext, builder);
                    }
                    glide = builder.createGlide();
                    for (GlideModule module : modules) {
                        module.registerComponents(applicationContext, glide);
                    }
                }
            }
        }
    
        return glide;
    }
    

    然后再看GlideBuilder如何初始化Glide的

    Glide createGlide() {
        if (sourceService == null) {
            final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
            sourceService = new FifoPriorityThreadPoolExecutor(cores);
        }
        if (diskCacheService == null) {
            diskCacheService = new FifoPriorityThreadPoolExecutor(1);
        }
    
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        if (bitmapPool == null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                int size = calculator.getBitmapPoolSize();
                bitmapPool = new LruBitmapPool(size);
            } else {
                bitmapPool = new BitmapPoolAdapter();
            }
        }
    
        if (memoryCache == null) {
            memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
        }
    
        if (diskCacheFactory == null) {
            diskCacheFactory = new InternalCacheDiskCacheFactory(context);
        }
    
        if (engine == null) {
            engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
        }
    
        if (decodeFormat == null) {
            decodeFormat = DecodeFormat.DEFAULT;
        }
    
        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }
    

    分别是创建获取源数据的线程池sourceService,获取磁盘缓存线程池diskCacheService,Bitmap缓存池bitmapPool,内存缓存memoryCache,磁盘缓存diskCacheFactory,资源处理引擎engine(负责获取资源并处理),然后创建Glide对象。

    Glide图片加载开始流程

    1. Gilde.with(Context context)获取RequestManager对象,该RequestManager对象创建之后保存在RequestManagerFragment或SupportRequestManagerFragment中,或者存储为applicationManager对象三种,也就是说RequestManager可能存在3个实例对象。以下是获取supportFragment情况的RequestManager对象方式
    public class RequestManagerRetriever implements Handler.Callback {
        public RequestManager get(FragmentActivity activity) {
            if (Util.isOnBackgroundThread()) {
                return get(activity.getApplicationContext());
            } else {
                assertNotDestroyed(activity);
                FragmentManager fm = activity.getSupportFragmentManager();
                return supportFragmentGet(activity, fm);
            }
        }
        
        RequestManager supportFragmentGet(Context context, FragmentManager fm) {
            SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    }
    
    
    1. RequestManager.load(String string)获取DrawableTypeRequest对象。当然还有其他的load方式,大同小异
    public class RequestManager implements LifecycleListener {
        public DrawableTypeRequest<String> load(String string) {
            return (DrawableTypeRequest<String>) fromString().load(string);
        }
    }
    
    1. DrawableTypeRequest.into(ImageView view)。最终还是进入到DrawableTypeRequest.into(Target target)方法。
    public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
        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.
                }
            }
    
            return into(glide.buildImageViewTarget(view, transcodeClass));
        }
    
        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())");
            }
    
            Request previous = target.getRequest();
    
            if (previous != null) {
                previous.clear();
                requestTracker.removeRequest(previous);
                previous.recycle();
            }
    
            Request request = buildRequest(target);
            target.setRequest(request);
            lifecycle.addListener(target);
            requestTracker.runRequest(request);
    
            return target;
        }
    }
    

    这里会移除释放target之前的请求,并且执行新的请求

    1. RequestTracker.runRequest开始执行请求
    public class RequestTracker {
        /**
         * Starts tracking the given request.
         */
        public void runRequest(Request request) {
            requests.add(request);
            if (!isPaused) {
                request.begin();
            } else {
                pendingRequests.add(request);
            }
        }
    }
    

    如果暂停,添加到挂起队列,否则begin开始执行请求。这里的request通常是GenericRequest,当然还有ThumbnailRequestCoordinator(可以同时处理完整图片和缩略图的请求),看它的组成,包含了full和thumb两个GenericRequest对象

    public class ThumbnailRequestCoordinator implements RequestCoordinator, Request {
        private Request full;
        private Request thumb;
        private RequestCoordinator coordinator;
    
        public ThumbnailRequestCoordinator() {
            this(null);
        }
    
        public ThumbnailRequestCoordinator(RequestCoordinator coordinator) {
            this.coordinator = coordinator;
        }
    
        public void setRequests(Request full, Request thumb) {
            this.full = full;
            this.thumb = thumb;
        }
        
        ...
    }
    
    1. 分析GenericRequest.begin(),这里会调用onSizeReady
    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));
        }
    }
    
    /**
     * A callback method that should never be invoked directly.
     */
    @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("Failed to load model: \'" + model + "\'"));
            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;
        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));
        }
    }
    

    在onSizeReady方法中可以看到,通过loadProvider获取ModelLoader对象和ResourceTranscoder对象,ModelLoader对象用于资源的加载,而ResourceTranscoder对象用于资源数据格式的转换。通过ModelLoader对象获取的DataFetcher对象就是用于获取源数据的,比如从网络读取图片数据,或者从SD卡读取本地图片数据等。后面将它们一起交给engine的load方法进行图片的加载处理。

    Glide资源加载流程,内存缓存加载

    Glide资源加载从Engine的load方法开始,流程如下

    1. 首先根据不同参数创建EngineKey对象作为键Key。
    2. 然后用EngineKey去内存缓存中查找,如果查找到,就回调ResourceCallback.onResourceReady表示资源找到了,并且会将当前资源从缓存中移除,添加到Map<Key, WeakReference<EngineResource<?>>> activeResources对象中,表示这是一个活动的资源,这里活动资源采用引用计数的方式管理。
    3. 如果没缓存中没有找到,则从activeResources活动资源中查找,它也是内存中的资源,只是独立出来使用引用计数进行管理。
    4. 如果activeResources活动资源中没有找到,则查找是否有EngineJob正在获取该资源,有的话添加回调到该EngineJob上面。
    5. 如果没有找到EngineJob,则创建新的EngineJob,创建DecodeJob,添加回调,创建EngineRunnable,然后执行EngineRunnable。EngineJob负责启动EngineRunnable,DecodeJob负责解析文件为Resource资源,EngineRunnable负责加载并解析得到Resource资源。

    也就是说,内存缓存分为两部分,弱引用持有的活动缓存和LruCache管理的非活动缓存,什么叫活动缓存,就是该图片有被用来显示就是活动的,如果没有被显示,就是非活动的。因此活动的图片缓存没有必要放入LruCache管理,因为此时它不应该被回收,而如果该图片不再被显示了,也就是release为0了之后,就会重新放入非活动缓存中由LruCache管理它的缓存,因此LruCache管理的内存缓存大小并不包含正在显示的图片。

    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 = 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);
        engineJob.start(runnable);
    
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    }
    

    EngineRunnable是一个Runnable,启动一个EngineRunnable就是将它交给diskCacheService线程池处理。然后你会发现,这里好像没有从网络或者本地加载原始图片资源的请求。它其实在EngineRunnable的run方法中有实现

    @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);
        }
    }
    
    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            return decodeFromCache();
        } else {
            return decodeFromSource();
        }
    }
    
    private Resource<?> decodeFromCache() throws Exception {
        Resource<?> result = null;
        try {
            result = decodeJob.decodeResultFromCache();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Exception decoding result from cache: " + e);
            }
        }
    
        if (result == null) {
            result = decodeJob.decodeSourceFromCache();
        }
        return result;
    }
    
    private Resource<?> decodeFromSource() throws Exception {
        return decodeJob.decodeFromSource();
    }
    

    以上分别有调用decodeJob的decodeResultFromCache(磁盘缓存中获取缩放处理后的图片资源,需要开启了DiskCacheStrategy.cacheResult),decodeSourceFromCache(磁盘缓存中获取原始图片资源,,需要开启了DiskCacheStrategy.cacheSource),decodeFromSource(从网络或者本地源获取原始资源)三种情况。因此decodeJob是负责从磁盘,网络/本地源加载资源的,获取之后采用回调的方式通知资源获取完毕。

    资源加载完成之后,同时还会执行transform转换和转码操作,也就是transformEncodeAndTranscode

    public Resource<Z> decodeFromSource() throws Exception {
        Resource<T> decoded = decodeSource();
        return transformEncodeAndTranscode(decoded);
    }
    
    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;
    }
    

    就是从一种Resource<R>转换成另一种Resource<T>。可以看到这里有调用transform,也就是设置transformation时,这里会产生作用的地方。

    private Resource<T> transform(Resource<T> decoded) {
        if (decoded == null) {
            return null;
        }
    
        Resource<T> transformed = transformation.transform(decoded, width, height);
        if (!decoded.equals(transformed)) {
            decoded.recycle();
        }
        return transformed;
    }
    

    然后是是会判断保存transform转换后的资源,然后是transcode转码成另一种Resource资源。

    Glide的转码ResourceTranscoder

    转码ResourceTranscoder接口也有很多实现,例如BitmapBytesTranscoder(将Bitmap转换为byte[])

    public class BitmapBytesTranscoder implements ResourceTranscoder<Bitmap, byte[]> {
        private final Bitmap.CompressFormat compressFormat;
        private final int quality;
    
        public BitmapBytesTranscoder() {
            this(Bitmap.CompressFormat.JPEG, 100);
        }
    
        public BitmapBytesTranscoder(Bitmap.CompressFormat compressFormat, int quality) {
            this.compressFormat = compressFormat;
            this.quality = quality;
        }
    
        @Override
        public Resource<byte[]> transcode(Resource<Bitmap> toTranscode) {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            toTranscode.get().compress(compressFormat, quality, os);
            toTranscode.recycle();
            return new BytesResource(os.toByteArray());
        }
    
        @Override
        public String getId() {
            return "BitmapBytesTranscoder.com.bumptech.glide.load.resource.transcode";
        }
    }
    

    其实也比较简单,就是一种数据类型的Resouce资源转换为另一个种数据类型的资源。

    Glide磁盘缓存资源加载

    无论是从磁盘缓存中获取原始图片资源还是缩放后图片资源,都是走的磁盘缓存资源加载渠道,区别只是key不一样。

    private Resource<T> loadFromCache(Key key) throws IOException {
        File cacheFile = diskCacheProvider.getDiskCache().get(key);
        if (cacheFile == null) {
            return null;
        }
    
        Resource<T> result = null;
        try {
            result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
        } finally {
            if (result == null) {
                diskCacheProvider.getDiskCache().delete(key);
            }
        }
        return result;
    }
    

    可以看到从磁盘缓存中获取资源文件,然后解码得到Resource。

    1. 这里的loadProvider是一个DataLoadProvider接口,它有很多实现,例如StreamFileDataLoadProvider(将输入流转换为文件)StreamBitmapDataLoadProvider(将输入流转换为Bitmap)等。
    2. 根据loadProvider.getCacheDecoder()获取ResourceDecoder对象,同样它也有对应的实现,例如FileDecoder(将文件转换为文件,也就是不需要额外处理),StreamBitmapDecoder(将InputStream输入流转换为Bitmap)。如果没获取到,则删除记录。

    Glide从网络/本地等源路径加载图片资源

    这里是从DecodeJob的decodeFromSource开始的

    class DecodeJob<A, T, Z> {
        public Resource<Z> decodeFromSource() throws Exception {
            Resource<T> decoded = decodeSource();
            return transformEncodeAndTranscode(decoded);
        }
        
        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;
        }
    
        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;
        }
    }
    

    可以看到这里有调用fetcher.loadData去获取数据,fetcher是DataFetcher接口对象,它的实现类有很多,例如HttpUrlFetcher(根据网络url获取输入流)

    public class HttpUrlFetcher implements DataFetcher<InputStream> {
    
        @Override
        public InputStream loadData(Priority priority) throws Exception {
            return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
        }
        
        ...
    }
    

    再比如StreamAssetPathFetcher(从assets目录的文件中获取输入流)

    public class StreamAssetPathFetcher extends AssetPathFetcher<InputStream> {
        public StreamAssetPathFetcher(AssetManager assetManager, String assetPath) {
            super(assetManager, assetPath);
        }
    
        @Override
        protected InputStream loadResource(AssetManager assetManager, String path) throws IOException {
            return assetManager.open(path);
        }
    
        @Override
        protected void close(InputStream data) throws IOException {
            data.close();
        }
    }
    

    因此,你只要实现DataFetcher接口,也可实现从你自己定义的模型中获取数据。

    资源加载完成回调

    资源加载回调是在EngineRunnable的run方法中处理的,加载失败执行onLoadFailed,加载成功执行onLoadComplete

    class EngineRunnable implements Runnable, Prioritized {
        @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);
            }
        }
        
        private void onLoadComplete(Resource resource) {
            manager.onResourceReady(resource);
        }
        
        private void onLoadFailed(Exception e) {
            if (isDecodingFromCache()) {
                stage = Stage.SOURCE;
                manager.submitForSource(this);
            } else {
                manager.onException(e);
            }
        }
    }
    

    那这个EngineRunnableManager类型对象manager是什么,它其实就是之前Engine类load方法中创建并传进去的EngineJob对象

    public class Engine implements EngineJobListener,
            MemoryCache.ResourceRemovedListener,
            EngineResource.ResourceListener {
            
            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);
            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对象添加回调
            engineJob.addCallback(cb);
            engineJob.start(runnable);
    
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Started new load", startTime, key);
            }
            return new LoadStatus(cb, engineJob);
        }
    }
    

    也就是图片加载完成是会回调EngineJob对象的onResourceReady方法,在onResourceReady方法中,会通过向Handler发送消息的方式,交给MainThreadCallback对象处理,然后又转交回EngineJob对象handleResultOnMainThread方法处理,在handleResultOnMainThread方法中会遍历之前注册的ResourceCallback对象,回调ResourceCallback对象的onResourceReady方法。

    class EngineJob implements EngineRunnable.EngineRunnableManager {
        private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
        
        @Override
        public void onResourceReady(final Resource<?> resource) {
            this.resource = resource;
            MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
        }
        
        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;
            }
        }
        
        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;
    
            // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
            // synchronously released by one of the callbacks.
            engineResource.acquire();
            listener.onEngineJobComplete(key, engineResource);
    
            //这里回调之前注册的ResourceCallback,通知资源加载完成
            for (ResourceCallback cb : cbs) {
                if (!isInIgnoredCallbacks(cb)) {
                    engineResource.acquire();
                    cb.onResourceReady(engineResource);
                }
            }
            // Our request is complete, so we can release the resource.
            engineResource.release();
        }
    }
    

    通过看之前代码,可以知道这个ResourceCallback对象是GenericRequest类中onSizeReady方法中传进去的,正是GenericRequest对象自己,这从逻辑上来也说的通,资源加载完成,通知请求的GenericRequest对象加载完成了。这里继续看回调完成的实现

    public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
            ResourceCallback {
            
        /**
         * A callback method that should never be invoked directly.
         */
        @SuppressWarnings("unchecked")
        @Override
        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);
        }
    
        /**
         * Internal {@link #onResourceReady(Resource)} where arguments are known to be safe.
         *
         * @param resource original {@link Resource}, never <code>null</code>
         * @param result object returned by {@link Resource#get()}, checked for type and never <code>null</code>
         */
        private void onResourceReady(Resource<?> resource, R result) {
            // We must call isFirstReadyResource before setting status.
            boolean isFirstResource = isFirstReadyResource();
            status = Status.COMPLETE;
            this.resource = resource;
    
            //回调target.onResourceReady
            if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                    isFirstResource)) {
                GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
                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);
            }
        }
        
        private void notifyLoadSuccess() {
          if (requestCoordinator != null) {
            requestCoordinator.onRequestSuccess(this);
          }
        }
    
    }
    

    可以看到会回调target.onResourceReady方法,这里看它的其中一个实现类ImageViewTarget和BitmapImageViewTarget

    public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
        @Override
        public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
            if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
                setResource(resource);
            }
        }
    
        protected abstract void setResource(Z resource);
    }
    
    public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
        public BitmapImageViewTarget(ImageView view) {
            super(view);
        }
    
        /**
         * Sets the {@link android.graphics.Bitmap} on the view using
         * {@link android.widget.ImageView#setImageBitmap(android.graphics.Bitmap)}.
         *
         * @param resource The bitmap to display.
         */
        @Override
        protected void setResource(Bitmap resource) {
            view.setImageBitmap(resource);
        }
    }
    

    可以看到这里是资源针对资源Bitmap加载完成时,给ImageView设置Bitmap对象来显示图片的。

    到这里从开始图片请求,到请求处理,到请求完成回调的流程就走通了,当然其中还有很多细节是走的不同分支,大家可以自行分析。

    相关文章

      网友评论

        本文标题:Glide原理之执行流程分析

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