Glide 网络请求分析二(3.7.0为例 3)

上一篇中 Glide.with(this).load("http://p1.pstatp.com/large/166200019850062839d3").into(iv); 加载图片,load() 方法执行到 RequestManager 中的

    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
        ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
                Glide.buildFileDescriptorModelLoader(modelClass, context);
        if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
            throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
                    + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                    + " Glide#register with a ModelLoaderFactory for your custom model class");
        }

        return optionsApplier.apply(
                new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }
    
    class OptionsApplier {

        public <A, X extends GenericRequestBuilder<A, ?, ?, ?>> X apply(X builder) {
            if (options != null) {
                options.apply(builder);
            }
            return builder;
        }
    }


    
也就是说,load() 返回的对象是 DrawableTypeRequest ,看下它的代码

    DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
            ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
            RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
        super(context, modelClass,
                buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                        GlideDrawable.class, null),
                glide, requestTracker, lifecycle);
        this.streamModelLoader = streamModelLoader;
        this.fileDescriptorModelLoader = fileDescriptorModelLoader;
        this.optionsApplier = optionsApplier;
    }


    
构造方法中的泛型 <ModelType> 此时的值是 <String> 类型,次构造方法调用了父类的super()方法,注意,它里面调用了 buildProvider() 方法,

    private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
            ModelLoader<A, InputStream> streamModelLoader,
            ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
            Class<R> transcodedClass,
            ResourceTranscoder<Z, R> transcoder) {
        if (streamModelLoader == null && fileDescriptorModelLoader == null) {
            return null;
        }

        if (transcoder == null) {
            transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
        }
        DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
                resourceClass);
        ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
                fileDescriptorModelLoader);
        return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
    }


这里面懵了,泛型太多,没关系,根据 buildProvider() 方法传入的参数,可以辨别 <A, Z, R> 对应的是 <String, GifBitmapWrapper, GlideDrawable> ,这个需要细心点就能发现; streamModelLoader 对应上一篇中的 StreamStringLoader,fileDescriptorModelLoader 暂时认为是null,resourceClass 是 GifBitmapWrapper.class,transcodedClass是 GlideDrawable.class; 继续看这个方法,创建 transcoder 和 dataLoadProvider,都是Glide中的方法返回的对象, modelLoader 是个包装类,封装了两个对象,然后就是 FixedLoadProvider 了,它的构造方法中需要 modelLoader, transcoder, dataLoadProvider 这三个对象。那么 transcoder 和 dataLoadProvider 是怎么来的?还是Glide 的构造方法

    Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
        ...

        dataLoadProviderRegistry = new DataLoadProviderRegistry();

        StreamBitmapDataLoadProvider streamBitmapLoadProvider =
                new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
        dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);

        FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
                new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
        dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);

        ImageVideoDataLoadProvider imageVideoDataLoadProvider =
                new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
        dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);

        GifDrawableLoadProvider gifDrawableLoadProvider =
                new GifDrawableLoadProvider(context, bitmapPool);
        dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);

        dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
                new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));

        dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());
        ...

        transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
                new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
        transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
                new GifBitmapWrapperDrawableTranscoder(
                        new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));

        ...
    }


这和上一篇中的 ModelLoader 方法类似,也是先用集合缓存数据,然后根据key值来找相对应的对象,transcoder = glide.buildTranscoder(resourceClass,transcodedClass) 中的形参为 GifBitmapWrapper.class 和 GlideDrawable.class,所以 transcoder 对应的是 GifBitmapWrapperDrawableTranscoder,它里面还包裹了一层 GlideBitmapDrawableTranscoder;dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class, resourceClass) 则 resourceClass 为
GifBitmapWrapper.class,所以 dataLoadProvider 是 ImageVideoGifDrawableLoadProvider, 它构造方法中参数包括 ImageVideoDataLoadProvider,而 ImageVideoDataLoadProvider 的构造方法包括 StreamBitmapDataLoadProvider,它们是聚合关系,一层层的,看看 ImageVideoGifDrawableLoadProvider 的构造
 

     public ImageVideoGifDrawableLoadProvider(DataLoadProvider<ImageVideoWrapper, Bitmap> bitmapProvider,
            DataLoadProvider<InputStream, GifDrawable> gifProvider, BitmapPool bitmapPool) {

        final GifBitmapWrapperResourceDecoder decoder = new GifBitmapWrapperResourceDecoder(
                bitmapProvider.getSourceDecoder(),
                gifProvider.getSourceDecoder(),
                bitmapPool
        );
        cacheDecoder = new FileToStreamDecoder<GifBitmapWrapper>(new GifBitmapWrapperStreamResourceDecoder(decoder));
        sourceDecoder = decoder;
        encoder = new GifBitmapWrapperResourceEncoder(bitmapProvider.getEncoder(), gifProvider.getEncoder());

        sourceEncoder = bitmapProvider.getSourceEncoder();
    }

这里面又是个封装类 GifBitmapWrapperResourceDecoder,它把形参 bitmapProvider 中的对象封装了一层, getSourceDecoder() 返回的对象就是 GifBitmapWrapperResourceDecoder。

继续回到 DrawableTypeRequest 中的构造方法,创建了 FixedLoadProvider 对象,然后把它当做参数传给了父类 DrawableRequestBuilder,它的构造也同样调用父类方法,继续参数上传到 GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> 中,注意泛型和 FixedLoadProvider 中的泛型是一一对应的,这里是 GenericRequestBuilder<String, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>,DrawableRequestBuilder 类继承
GenericRequestBuilder 时标明了后面三个泛型的对象类型,这个可以先记住,下面分析会用到。

Glide.with(this).load("http://p1.pstatp.com/large/166200019850062839d3").into(iv) 的 into() 方法,是在 DrawableRequestBuilder 中,它调用了父类 GenericRequestBuilder 中的方法,

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

第一行是校验是否在主线程,我们只看最后一行, buildImageViewTarget() 方法最终调用 ImageViewTargetFactory 中的方法

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

此刻传入的transcodeClass类型是 GlideDrawable.class,所以返回的是 GlideDrawableImageViewTarget 对象,继续看 into() 方法

    public <Y extends Target<TranscodeType>> Y into(Y target) {
        ...

        Request request = buildRequest(target);
        target.setRequest(request);
        lifecycle.addListener(target);
        requestTracker.runRequest(request);

        return target;
    }

注意两行代码 buildRequest(target) 和 requestTracker.runRequest(request),

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

    private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
        ...
        } else {
            // Base case: no thumbnail.
            return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
        }
    }
    private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
            RequestCoordinator requestCoordinator) {
        return GenericRequest.obtain(...);
    }

request 就是 GenericRequest 对象;requestTracker 是哪里来的呢?看代码发现,它是 RequestManager 的构造方法new出来的 RequestTracker,它里面代码比较简单,有两个集合,装的是请求的 request 和 待请求的 request, requestTracker.runRequest(request) 方法为

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

RequestManager 也会受 Lifecycle 的回调,在 Activity 中,Activity 切入前后台时,RequestManager 中的onStart()和onStop()方法会被调用

    @Override
    public void onStart() {
        resumeRequests();
    }
    public void resumeRequests() {
        Util.assertMainThread();
        requestTracker.resumeRequests();
    }    
    
    @Override
    public void onStop() {
        pauseRequests();
    }
    public void pauseRequests() {
        Util.assertMainThread();
        requestTracker.pauseRequests();
    }    

因此,requestTracker.runRequest(request) 方法中的代码就好理解了,request.begin() 执行的是 GenericRequest 的 begin() 方法

    @Override
    public void begin() {
        ...
        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            target.onLoadStarted(getPlaceholderDrawable());
        }
        ...
    }

我们上述代码,没有指定图片大小,所以会执行 target.getSize(this) 代码,它里面经历一些计算然后回调到本类中的 onSizeReady(overrideWidth,overrideHeight) 方法,target.onLoadStarted() 方法则是加载占位图,看下 ImageViewTarget 中的方法就明白了。这里说下 target.getSize() 方法,它是在 ViewTarget 中,用 SizeDeterminer 类中的方法,这里面会有些逻辑换算,有个技巧点,那就是添加集合存储cb回调,用 ViewTreeObserver 监听view绘制前的回调方法,重新获取view的宽和高,然后回调到 GenericRequest 中的 onSizeReady() 方法中

    @Override
    public void onSizeReady(int width, int 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();
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        ...
    }

终于到这一步了,看到 modelLoader 和 dataFetcher,modelLoader 是 FixedLoadProvider 中的 modelLoader,是在 DrawableTypeRequest 的 buildProvider()方法中创建的 ImageVideoModelLoader,dataFetcher 获取的对象是封装了HttpUrlFetcher 的 ImageVideoFetcher 对象;看下 ImageVideoModelLoader 的方法

    @Override
    public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
        DataFetcher<InputStream> streamFetcher = null;
        if (streamLoader != null) {
            streamFetcher = streamLoader.getResourceFetcher(model, width, height);
        }
        ...
        if (streamFetcher != null || fileDescriptorFetcher != null) {
            return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
        } else {
            return null;
        }
    }

它封装的 streamLoader 就是 StreamStringLoader 对象,getResourceFetcher(model, width, height) 返回的 streamFetcher 是 HttpUrlFetcher,然后把它封装到 ImageVideoFetcher 中,为什么是 HttpUrlFetcher,这就是上一篇中重点分析的东西。transcoder 则是上面分析的 FixedLoadProvider 构造方法中第二个参数transcoder 即 GifBitmapWrapperDrawableTranscoder 对象;engine 则是默认的 Engine 对象;接下来是Engine 的 load()方法了

    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) {
        ...

        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);
        ...
        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        ...

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

        ...
        return new LoadStatus(cb, engineJob);
    }

一开始通过 fetcher 获取到 id,然后用一系列相关参数传入 EngineKey 中,这个 key 就是该图片的唯一标示,它是缓存模块的一个关键,只要它里面的参数有任何一遍变化了,则会认为是新图片,就会重新创建并缓存;loadFromCache() 和 loadFromActiveResources() 是从缓存中获取,如果有值,直接回调 cb 的方法,这个放到下篇缓存的文章中,这篇先继续说网络,继续往下看,这里有三个对象 EngineJob、DecodeJob 和 EngineRunnable,EngineRunnable 实现了 Runnable 接口,耗时操作比如从本地读取数据或者从网络获取数据,都是从这里面执行; DecodeJob 更像是中转器的控制类,负责逻辑调用;EngineJob 则是提供线程池及子线程切换到主线程并把值给回调回去,回调 cb 是 ResourceCallback,cb 通过 engineJob.addCallback(cb) 被添加进去,engineJob.start(runnable) 则是执行子线程,看看它的方法

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

    @Override
    public void submitForSource(EngineRunnable runnable) {
        future = sourceService.submit(runnable);
    }

这里的 diskCacheService 和 sourceService 的源头是 GlideBuilder 中的 createGlide() 方法,都是 FifoPriorityThreadPoolExecutor,里面核心线程数见代码;继续看 EngineRunnable 类,构造方法中 stage = Stage.CACHE,再看看 run() 方法

    @Override
    public void run() {
        ...
        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 (resource == null) {
            onLoadFailed(exception);
        } else {
            onLoadComplete(resource);
        }
    }

    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            return decodeFromCache();
        } else {
            return decodeFromSource();
        }
    }
     private boolean isDecodingFromCache() {
        return stage == Stage.CACHE;
    }


       
此方法中,会执行 decode() 方法,此时 isDecodingFromCache() 为true,执行 decodeFromCache(),这里会通过 DecodeJob 查找磁盘缓存,咱们默认找不到,返回的是 null,接下来就会执行 onLoadFailed(exception) ,

    private void onLoadFailed(Exception e) {
        if (isDecodingFromCache()) {
            stage = Stage.SOURCE;
            manager.submitForSource(this);
        } else {
            manager.onException(e);
        }
    }

这里 isDecodingFromCache() 仍为true,改变 stage 的状态值,这里 manager 就是构造方法传进来的 EngineJob engineJob 对象,所以这次就是 sourceService 这个线程池执行 runnable 本身了,再次看 run() 方法,这次是 decodeFromSource() 方法

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

    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);
            ...
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }


好吧,看到 fetcher.loadData(priority) 这行代码,fetcher 是 ImageVideoFetcher 类型,是一个封装类,所以 fetcher.loadData(priority) 执行的是 ImageVideoFetcher 的 loadData(Priority priority) 方法

        @Override
        public ImageVideoWrapper loadData(Priority priority) throws Exception {
            InputStream is = null;
            if (streamFetcher != null) {
                try {
                    is = streamFetcher.loadData(priority);
                } catch (Exception e) {
                    ...
                }
            }
            ...
            return new ImageVideoWrapper(is, fileDescriptor);
        }

网络请求就是这一刻触发了,streamFetcher 是 HttpUrlFetcher 类型,返回的 data 是ImageVideoWrapper类型,里面封装了InputStream流。然后调用 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;
    }

这里有个缓存策略,是保存原图、转换后的图还是都保存,默认是缓存转换后的图,这里走到 else 里面, loadProvider.getSourceDecoder() 代码中 loadProvider 是LoadProvider类型 ChildLoadProvider,它封装了 FixedLoadProvider,执行的还是 FixedLoadProvider 中的方法,然后调用ImageVideoGifDrawableLoadProvider中的 getSourceDecoder() 方法,返回的 sourceDecoder 是个 GifBitmapWrapperResourceDecoder 类型,decode(data,width, height) 方法则比较有意思,就是一串线,GifBitmapWrapperResourceDecoder(ImageVideoGifDrawableLoadProvider) --》 ImageVideoDataLoadProvider --》 StreamBitmapDataLoadProvider --> StreamBitmapDecoder --> Downsampler,在 GifBitmapWrapperResourceDecoder 中调用,Downsampler 中返回 Resource<Bitmap>,然后再封装一层变为 GifBitmapWrapper,再创建 GifBitmapWrapperResource ,继续回到 DecodeJob 中的 decodeFromSource()方法,

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

此时 decoded 为 GifBitmapWrapperResource,调用 transformEncodeAndTranscode(decoded) 进行图片的转换,这里先忽略,后面的文章会分析。回到EngineRunnable中的 run() 方法,获取到了值,就执行 onLoadComplete(resource) 方法

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

看看 EngineJob 中的 onResourceReady() 方法,这里用 Handler 发送一条消息,切回了主线程,执行了 handleResultOnMainThread() 方法

    private void handleResultOnMainThread() {
        ...
        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                cb.onResourceReady(engineResource);
            }
        }
        ...
    }

看回调,这里的 cb 是在 Engine 的 load() 方法中添加的,执行的是 GenericRequest 中的 onResourceReady(Resource<?> resource) 方法,最终执行了重载的方

    private void onResourceReady(Resource<?> resource, R result) {
        ...
        if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
                isFirstResource)) {
            GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
            target.onResourceReady(result, animation);
        }
        ...
    }

我们用 Glide 的时候可以设置加载图片成功或失败的回调,就是这里执行成功的回调,如果返回值是true,则会被消耗掉;如果设置为false或者没设置监听回调,则会执行 target.onResourceReady(result, animation) 的方法,这里 target 是 GlideDrawableImageViewTarget,

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

    @Override
    protected void setResource(GlideDrawable resource) {
        view.setImageDrawable(resource);
    }

这里面的代码比价好理解,先调用父类的方法,父类中会调用 setResource() 方法,就这样加载图片了。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值