Glide源码解析03-into

Glide源码解析03-into#

最简单的Glide调用,如下所示,下面将根据Glide的调用顺序,进行源码解析。

Glide.with(this)
        .load(uri)
        .into(img);

into方法

在上一步load方法中,我们初始化了一些数据,并返回了GenericRequestBuilder或其子类。现在,来看GenericRequestBuilder.into()

3.0 GenericRequestBuilder#into()

前面首先会判断当前线程,只有主线程才能继续执行。
并且,如果没有设置过transform()或centerCrop,那么以ImageView的scaleType属性为准。

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread(); //判断是否是主线程,如果不是会抛出异常。
    //...

	//如果没有设置transform()或centerCrop(),那么以ImageView的scaleType属性为准
    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));
}  
3.1 glide.buildImageViewTarget

来看Glide.buildImageViewTarget,在这个方法中会调用ImageViewTargetFactory#buildTarget()

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

这是个工厂方法,根据当前传入的clazz参数返回相应的类

  1. 如果之前调用过asBitmap()方法,那么会返回BitmapImageViewTarget对象
  2. 否则一般都是返回GlideDrawableImageViewTarget对象
  3. 其他情况通常用不到

注意这里
BitmapImageViewTarget和DrawableImageViewTarget就是具体是设置图片到ImageView的实现类,以DrawableImageViewTarget为例,可以看到view.setImageDrawable(resource)

public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {

  public DrawableImageViewTarget(ImageView view) {
    super(view);
  }

  /**
   * @deprecated Use {@link #waitForLayout()} instead.
   */
  // Public API.
  @SuppressWarnings({"unused", "deprecation"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }

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

回到1.0.0,我们再来看into方法

3.2 GenericRequestBuilder#into(Y target)

在这个方法中,主要会构建出一个Request对象,并执行这个Request对象。

public <Y extends Target<TranscodeType>> Y into(Y target) {
    Util.assertMainThread();
    //...

    Request previous = target.getRequest();

    if (previous != null) {
        previous.clear();
        requestTracker.removeRequest(previous);
        previous.recycle();
    }

	//1.2.1 构建出了一个Request对象
    Request request = buildRequest(target);
    target.setRequest(request);
    lifecycle.addListener(target);
	//1.2.3 执行这个request
    requestTracker.runRequest(request);

    return target;
}
3.3 buildRequest

先来看buildRequest,这里分成三种情况,但最终都会调用obtainRequest

private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
    if (thumbnailRequestBuilder != null) {
		//设置过thumbnail(GenericRequestBuilder)或thumbnail(
        DrawableRequestBuilder)会调用这里
        //...
        Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
       	//...
        coordinator.setRequests(fullRequest, thumbRequest);
        return coordinator;
    } else if (thumbSizeMultiplier != null) {
		//设置过 thumbnail(float)会调用这里
        //...
        Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
        coordinator.setRequests(fullRequest, thumbnailRequest);
        return coordinator;
    } else {
		//没有设置过thumbnail(缩略图)会调用这里
        //...
        return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
    }
}

private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
        RequestCoordinator requestCoordinator) {
    return GenericRequest.obtain(
            loadProvider,
            model,
            signature,
            context,
            priority,
            target,
            sizeMultiplier,
            placeholderDrawable,
            placeholderId,
            errorPlaceholder,
            errorId,
            fallbackDrawable,
            fallbackResource,
            requestListener,
            requestCoordinator,
            glide.getEngine(),
            transformation,
            transcodeClass,
            isCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
}
3.3.2 GenericRequestBuilder#obtainRequest

来看obtainRequest,首先如果request没有初始化,则new GenericRequest对象。接着调用GenericRequest#into方法 ,其内部是一些赋值的代码,将传入的这些参数赋值到GenericRequest的成员变量中。

public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(...很多参数...) {
    //...
	if (request == null) {
		//创建GenericRequest对象
        request = new GenericRequest<A, T, Z, R>();
    }
	//内部是一些赋值的代码,将传入的这些参数赋值到GenericRequest的成员变量当中
    request.init(loadProvider,
            model,
            signature,
            context,
            priority,
            target,
            sizeMultiplier,
            placeholderDrawable,
            placeholderResourceId,
            errorDrawable,
            errorResourceId,
            fallbackDrawable,
            fallbackResourceId,
            requestListener,
            requestCoordinator,
            engine,
            transformation,
            transcodeClass,
            isMemoryCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
    return request;
}  

####3.4 ReuqestTracker#runRequest ####
回到3.2,来看runRequest,这里是真正执行的地方。可以看到如果没有处于暂停状态,会直接调用request.begein(),如果处于暂停状态,那么先添加到队列中,等恢复到正常状态时,会再调用request.begin()。即无论如何都会调用request.begin()

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

那这个request到底是哪类类呢? 就是我们前面在 1.2.2 GenericRequestBuilder#obtainRequest中分析的GenericRequest。
在这里无论是onSizeReady还是target.getSize,最终都会调用onSizeReady。

@Override
public void begin() {
	//...
	if (model == null) {
		//model是存储url的,这里会调用setErrorPlaceholder,从而最终调用setImageDrawable
        onException(null);
        return;
	}
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
		//使用了override() API指定了固定的宽高 调用这里
        onSizeReady(overrideWidth, overrideHeight);
    } else {
		//没有使用了override() API指定固定的宽高 调用这里
		//这个target.getSize()方法的内部会根据ImageView的layout_width和layout_height值做一系列的计算,来算出图片应该的宽高。
        target.getSize(this);
    }

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

onSizeReady会确定图片的宽高并调用engine.load来执行加载。

public void onSizeReady(int width, int height) {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
        return;
    }
    status = Status.RUNNING;

    width = Math.round(sizeMultiplier * width);
    height = Math.round(sizeMultiplier * height);

	//loadProvider内部封装了GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider,
	//这个对象是从load方法中构建出来的 -> 具体在DrawableTypeRequest构造方法中
	//获取ImageVideoModelLoader
    ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
	//获取ImageVideoFetcher
    final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

    if (dataFetcher == null) {
        onException(new Exception("Failed to load model: \'" + model + "\'"));
        return;
    }
	//获取GifBitmapWrapperDrawableTranscoder
    ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadedFromMemoryCache = true;
	//[重点] 
    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));
    }
}
3.7 engine.load

这个方法中分为两步,第一步处理缓存,第二步真正执行加载,
构建出EngineJob,并把callback (callback是GenericRequest对象)添加到EngineJob中,并且执行刚new出来的EngineRunnable

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

   	//...
    return new LoadStatus(cb, engineJob);
}
3.8 EngineRunnable#run()

engineJob.start()会执行EngineRunnable的run方法。

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

    Exception exception = null;
    Resource<?> resource = null;
    try {
		//1.3.0 解码
        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;
    }

	//1.3.2 加载结果
    if (resource == null) {
        onLoadFailed(exception);
    } else {
        onLoadComplete(resource);
    }
}
3.9 decode

decode方法进行了解码,返回Resource对象,详情看 Glide源码解析04-decode

3.10 onLoadFailed or onLoadComplete

如果resource为null,则执行加载失败的逻辑,如果不为null,则执行加载成功的逻辑。详情看Glide源码解析05-onLoadComplete

###更多
Glide源码解析01-with
Glide源码解析02-load
Glide源码解析03-into
Glide源码解析04-decode
Glide源码解析05-onLoadComplete
Glide源码解析06-Glide流程图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值