Glide簡析

隨著Android開發(fā)的愈漸火熱,各種Android的圖片加載庫也曾出不窮,比較有名的有:Fresco、PicassoUniversal Image Loader等等。在這篇文章中,我會通過源碼來簡單地分析一下Glide使用時所發(fā)生的事情。

使用方法

對于Glide的使用方法不是本文的重點,在這里就不多說了,這里貼出Glide的Github地址,如果對使用方法有什么疑問的就上官方去看看吧。這里我們從Glide最簡單的三行使用方法入手進行分析:

Glide.with(...)
        .load(...)
        .into(...);

流程分析

首先我們進入Glide類看看with()方法:

public static RequestManager with(Context context) {   
    RequestManagerRetriever retriever = RequestManagerRetriever.get(); 
    return retriever.get(context);
}

我們可以看到with()方法是Glide類中的一個靜態(tài)方法,它會創(chuàng)建一個RequestManagerRetriever對象,在這里我們先不看這個類在創(chuàng)建過程中發(fā)生的事情,先看看它通過傳入的Context對象所返回的這個RequestManager對象。

對于RequestManager這個類,官方文檔是這樣描述的:
A class for managing and starting requests for Glide. Can use activity, fragment and connectivity lifecycle events to intelligently stop, start, and restart requests. Retrieve either by instantiating a new object, or to take advantage built in Activity and Fragment lifecycle handling, use the static Glide.load methods with your Fragment or Activity.
本人英文一般,就不逐字逐句地翻譯了??傊瑢τ?strong>RequestManager這個類的定位就是對圖片加載請求進行管理的類,并且它會根據(jù)與其產生聯(lián)系的Context對象的生命周期來管理圖片加載的過程。因此,圖片資源加載進ImageView的過程事實上是由它來一手掌管的。

知道了這些,我們接下來來看看它的load()方法,也就是我們將資源路徑傳入的這個方法,這里我們以傳入一個Uri為例:

public DrawableTypeRequest<Uri> load(Uri uri) {
    return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}

在這個方法中使用了DrawableTypeRequest中的load()方法去加載這個uri:

public DrawableRequestBuilder<ModelType> load(ModelType model) {    
    super.load(model);
    return this;
}

這個方法的泛型參數(shù)ModelType在這里所對應的實際類型就是我們傳入的資源類型Uri,并且調用了DrawableRequestBuilder的父類方法load()來處理。

GenericRequestBuilder就是DrawableRequestBuilder的父類,這個類及其子類的作用就是用于請求加載的。我們來看看里面剛剛提到的load()方法:

public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
    this.model = model;
    isModelSet = true;
    return this;
}

這里我們發(fā)現(xiàn),load()方法僅僅是將資源——這里就是我們的圖片資源Uri賦值給了一個變量model,至于圖片資源究竟是怎么加載進ImageView的,我們回到這里實際進行加載請求的類DrawableRequestBuilder去看看它當中被我們最后調用的into()方法:

public Target<GlideDrawable> into(ImageView view) {
    return super.into(view);
}

load()方法相同,這里也調用了父類GenericRequestBuilderinto()方法:

public Target<TranscodeType> into(ImageView view) {
    ......
    return into(glide.buildImageViewTarget(view, transcodeClass));
}

對于這個方法我們只看最后一句代碼。在這里又再次回到一開始的Glide,并調用了其中的buildImageViewTarget()方法,而在這個方法中傳入了一個GlideDrawable對象transcodedClass

<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}

我們繼續(xù)跟蹤下去:

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

經過反復地輾轉我們終于發(fā)現(xiàn)了上面我們傳入into()方法中的是一個和我們所要將圖片加載進的ImageView相關的GlideDrawableImageViewTarget對象。我們先記住這一點,不繼續(xù)深究下去,先回頭看看那個GenericRequestBuilder中的into()方法:

public <Y extends Target<TranscodeType>> Y into(Y target) {
    ......
    Request request = buildRequest(target);
    target.setRequest(request);
    ......
    requestTracker.runRequest(request);

    return target;
}

這段代碼所做的事情根據(jù)方法名很容易就能猜到,它先根據(jù)傳入的一個Target對象創(chuàng)建一個Request,并將兩者建立關聯(lián),最后執(zhí)行加載請求。

這里我們反過來會發(fā)現(xiàn),這個Target的實際對象就是我們剛剛所說的那個GlideDrawable,另外談到請求,是不是想到我們前面load()進去的那個Uri對象了呢?一陣云里霧里,整個內容終于聯(lián)系了起來,那么我們就先來看看這個Request對象究竟是怎么創(chuàng)建的:

private Request buildRequest(Target<TranscodeType> target) {
    ......
    return buildRequestRecursive(target, null);
}

這里又將那個Target對象傳進一個buildRequestRecursive()方法中:

private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
    ......
    return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}

對于這個方法,我們重點來關注一下其中的一行代碼,其中涉及了obtainRequest()方法,這個方法有四個參數(shù),其中最重要的就是第一個,這里將剛剛的Target對象給傳了進去,我們接下來看一下這個方法:

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

這個方法中只做了一件事,調用了GenericRequest類的靜態(tài)方法obtain(),并且傳入了很多的參數(shù),這里注意其中的參數(shù)target,即上面的GlideDrawableImageViewTarget對象,另外還有就是這里執(zhí)行了Glide中的getEngine()方法,還有資源模型model。然后繼續(xù)往下看:

public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
        LoadProvider<A, T, Z, R> loadProvider,
        A model,
        Key signature,
        Context context,
        Priority priority,
        Target<R> target,
        float sizeMultiplier,
        Drawable placeholderDrawable,
        int placeholderResourceId,
        Drawable errorDrawable,
        int errorResourceId,
        Drawable fallbackDrawable,
        int fallbackResourceId,
        RequestListener<? super A, R> requestListener,
        RequestCoordinator requestCoordinator,
        Engine engine,
        Transformation<Z> transformation,
        Class<R> transcodeClass,
        boolean isMemoryCacheable,
        GlideAnimationFactory<R> animationFactory,
        int overrideWidth,
        int overrideHeight,
        DiskCacheStrategy diskCacheStrategy) {
    @SuppressWarnings("unchecked")
    GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
    if (request == null) {
        request = new GenericRequest<A, T, Z, R>();
    }
    request.init(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;
}

這一段看上去有點長,但是其實也只涉及到了一個方法init(),這個方法同樣接受了很多參數(shù),并且在這個方法中,做的也只有一件事,就是將這些傳入的參數(shù)一一賦值給GenericRequest的成員變量:

private void init(
        LoadProvider<A, T, Z, R> loadProvider,
        A model,
        Key signature,
        Context context,
        Priority priority,
        Target<R> target,
        float sizeMultiplier,
        Drawable placeholderDrawable,
        int placeholderResourceId,
        Drawable errorDrawable,
        int errorResourceId,
        Drawable fallbackDrawable,
        int fallbackResourceId,
        RequestListener<? super A, R> requestListener,
        RequestCoordinator requestCoordinator,
        Engine engine,
        Transformation<Z> transformation,
        Class<R> transcodeClass,
        boolean isMemoryCacheable,
        GlideAnimationFactory<R> animationFactory,
        int overrideWidth,
        int overrideHeight,
        DiskCacheStrategy diskCacheStrategy) {
    this.loadProvider = loadProvider;
    this.model = model;
    this.signature = signature;
    this.fallbackDrawable = fallbackDrawable;
    this.fallbackResourceId = fallbackResourceId;
    this.context = context.getApplicationContext();
    this.priority = priority;
    this.target = target;
    this.sizeMultiplier = sizeMultiplier;
    this.placeholderDrawable = placeholderDrawable;
    this.placeholderResourceId = placeholderResourceId;
    this.errorDrawable = errorDrawable;
    this.errorResourceId = errorResourceId;
    this.requestListener = requestListener;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.transformation = transformation;
    this.transcodeClass = transcodeClass;
    this.isMemoryCacheable = isMemoryCacheable;
    this.animationFactory = animationFactory;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.diskCacheStrategy = diskCacheStrategy;
    status = Status.PENDING;
    ......
}

到這里對于加載請求的設置幾本完成,我們再回去看看那句運行加載的代碼requestTracker.runRequest(request);所做的具體的事情:

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

這里調用了剛剛設置好的Request對象的begin()方法,而這里的Request對象的實際類型就是上面我們所看到的GenericRequest對象。于是,我們來看看它的begin()方法:

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

這里我們需要關注的就是一個Target對象的onLoadStarted()方法,在這里我們記起這個Target對象的實際類型就是上面的init()方法中所設置的GlideDrawableImageViewTarget對象。也許你會認為這個begin()方法就是資源加載進ImageView的關鍵,但是當我們點進去查看它的begin()方法時卻發(fā)現(xiàn)并不如我們所想,它只是為我們的ImageView設置了一個占位圖,并沒有做其他的事情。但是我們在查看GlideDrawableImageViewTarget的源碼的時候,我們發(fā)現(xiàn)了這么一個方法onResourceReady(),在這個方法中有這么一句代碼:

setResource(resource);

接著看看setResource()

public void setResource(GlideDrawable resource) {
    view.setImageDrawable(resource);
}

這里的resource我們猜應該就是圖片資源了,也會是說這里所做的事情就是最后將圖片呈現(xiàn)在ImageView上,但程序究竟是怎么到這里的呢,我們想到了上面的getEngine()方法,于是我們來看看這里所做的事情:

Engine getEngine() {
    return engine;
}

這個Engine又是一個非常重要的類,我們來看看這個類的官方介紹:
Responsible for starting loads and managing active and cached resources.
我們發(fā)現(xiàn)這個類就是真正用來管理加載的類。但是這個不是我這篇文章的重點,關于它所作的事情我會在后面的文章中對它進行簡析。既然這個Engine對象是用來加載資源的,那么我們就想到了一開始的那個上面另外一個要記住的model,看看它們是怎么運用的。要想知道這到底是怎么使用的,我在這里貼出最重要的一段:

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

這個方法是EngineRunnable類中的,這個類從名字就可以看出來它的作用就是響應Engine的。而這里的onResourceReady()則是觸發(fā)了GenericRequest中的一個回調onResourceReady()

public void onResourceReady(Resource<?> resource) {
    ......
    onResourceReady(resource, (R) received);
}

這里又調用了該類中的一個重載方法:

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

這里我們看到了,這個方法使用到了model,而這個方法則屬于一個RequestListener回調接口,這個回調接口究竟會在哪里被調用呢,其實就是我們上面提到的GlideDrawableImageViewTargetonResourceReady(),而在這個方法中,另一個參數(shù)target在這里的實際類型就是GlideDrawableImageViewTarget。到這里我們終于是弄明白整個圖片資源的加載過程了。

這里用了大量的篇幅大致地給大家介紹了一下Glide的大致加載流程,但是在這其中我們還有很多關于圖片加載的所必需弄懂的細節(jié)并沒有進行介紹,但是這篇文章就先到這里,關于這些東西我會在后續(xù)的文章中盡我所能地分析給大家。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容