Glide簡(jiǎn)析

隨著Android開發(fā)的愈漸火熱苍匆,各種Android的圖片加載庫(kù)也曾出不窮系冗,比較有名的有:Fresco淹仑、PicassoUniversal Image Loader等等令杈。在這篇文章中走敌,我會(huì)通過(guò)源碼來(lái)簡(jiǎn)單地分析一下Glide使用時(shí)所發(fā)生的事情。

使用方法

對(duì)于Glide的使用方法不是本文的重點(diǎn)这揣,在這里就不多說(shuō)了悔常,這里貼出Glide的Github地址,如果對(duì)使用方法有什么疑問(wèn)的就上官方去看看吧给赞。這里我們從Glide最簡(jiǎn)單的三行使用方法入手進(jìn)行分析:

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

流程分析

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

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

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

對(duì)于RequestManager這個(gè)類,官方文檔是這樣描述的:
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.
本人英文一般柑蛇,就不逐字逐句地翻譯了芥挣。總之耻台,對(duì)于RequestManager這個(gè)類的定位就是對(duì)圖片加載請(qǐng)求進(jìn)行管理的類空免,并且它會(huì)根據(jù)與其產(chǎn)生聯(lián)系的Context對(duì)象的生命周期來(lái)管理圖片加載的過(guò)程。因此盆耽,圖片資源加載進(jìn)ImageView的過(guò)程事實(shí)上是由它來(lái)一手掌管的蹋砚。

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

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

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

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

這個(gè)方法的泛型參數(shù)ModelType在這里所對(duì)應(yīng)的實(shí)際類型就是我們傳入的資源類型Uri循榆,并且調(diào)用了DrawableRequestBuilder的父類方法load()來(lái)處理。

GenericRequestBuilder就是DrawableRequestBuilder的父類墨坚,這個(gè)類及其子類的作用就是用于請(qǐng)求加載的秧饮。我們來(lái)看看里面剛剛提到的load()方法:

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

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

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

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

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

對(duì)于這個(gè)方法我們只看最后一句代碼帽撑。在這里又再次回到一開始的Glide振劳,并調(diào)用了其中的buildImageViewTarget()方法,而在這個(gè)方法中傳入了一個(gè)GlideDrawable對(duì)象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)");
    }
}

經(jīng)過(guò)反復(fù)地輾轉(zhuǎn)我們終于發(fā)現(xiàn)了上面我們傳入into()方法中的是一個(gè)和我們所要將圖片加載進(jìn)的ImageView相關(guān)的GlideDrawableImageViewTarget對(duì)象油狂。我們先記住這一點(diǎn),不繼續(xù)深究下去寸癌,先回頭看看那個(gè)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ù)傳入的一個(gè)Target對(duì)象創(chuàng)建一個(gè)Request,并將兩者建立關(guān)聯(lián)蒸苇,最后執(zhí)行加載請(qǐng)求磷蛹。

這里我們反過(guò)來(lái)會(huì)發(fā)現(xiàn),這個(gè)Target的實(shí)際對(duì)象就是我們剛剛所說(shuō)的那個(gè)GlideDrawable溪烤,另外談到請(qǐng)求味咳,是不是想到我們前面load()進(jìn)去的那個(gè)Uri對(duì)象了呢?一陣云里霧里檬嘀,整個(gè)內(nèi)容終于聯(lián)系了起來(lái)槽驶,那么我們就先來(lái)看看這個(gè)Request對(duì)象究竟是怎么創(chuàng)建的:

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

這里又將那個(gè)Target對(duì)象傳進(jìn)一個(gè)buildRequestRecursive()方法中:

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

對(duì)于這個(gè)方法,我們重點(diǎn)來(lái)關(guān)注一下其中的一行代碼鸳兽,其中涉及了obtainRequest()方法掂铐,這個(gè)方法有四個(gè)參數(shù),其中最重要的就是第一個(gè)揍异,這里將剛剛的Target對(duì)象給傳了進(jìn)去全陨,我們接下來(lái)看一下這個(gè)方法:

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

這個(gè)方法中只做了一件事,調(diào)用了GenericRequest類的靜態(tài)方法obtain()衷掷,并且傳入了很多的參數(shù)辱姨,這里注意其中的參數(shù)target,即上面的GlideDrawableImageViewTarget對(duì)象戚嗅,另外還有就是這里執(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;
}

這一段看上去有點(diǎn)長(zhǎng),但是其實(shí)也只涉及到了一個(gè)方法init()镜悉,這個(gè)方法同樣接受了很多參數(shù)祟辟,并且在這個(gè)方法中,做的也只有一件事侣肄,就是將這些傳入的參數(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;
    ......
}

到這里對(duì)于加載請(qǐng)求的設(shè)置幾本完成旧困,我們?cè)倩厝タ纯茨蔷溥\(yùn)行加載的代碼requestTracker.runRequest(request);所做的具體的事情:

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

這里調(diào)用了剛剛設(shè)置好的Request對(duì)象的begin()方法,而這里的Request對(duì)象的實(shí)際類型就是上面我們所看到的GenericRequest對(duì)象稼锅。于是吼具,我們來(lái)看看它的begin()方法:

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

這里我們需要關(guān)注的就是一個(gè)Target對(duì)象的onLoadStarted()方法,在這里我們記起這個(gè)Target對(duì)象的實(shí)際類型就是上面的init()方法中所設(shè)置的GlideDrawableImageViewTarget對(duì)象矩距。也許你會(huì)認(rèn)為這個(gè)begin()方法就是資源加載進(jìn)ImageView的關(guān)鍵拗盒,但是當(dāng)我們點(diǎn)進(jìn)去查看它的begin()方法時(shí)卻發(fā)現(xiàn)并不如我們所想,它只是為我們的ImageView設(shè)置了一個(gè)占位圖锥债,并沒(méi)有做其他的事情陡蝇。但是我們?cè)诓榭?strong>GlideDrawableImageViewTarget的源碼的時(shí)候,我們發(fā)現(xiàn)了這么一個(gè)方法onResourceReady()哮肚,在這個(gè)方法中有這么一句代碼:

setResource(resource);

接著看看setResource()

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

這里的resource我們猜應(yīng)該就是圖片資源了登夫,也會(huì)是說(shuō)這里所做的事情就是最后將圖片呈現(xiàn)在ImageView上,但程序究竟是怎么到這里的呢允趟,我們想到了上面的getEngine()方法恼策,于是我們來(lái)看看這里所做的事情:

Engine getEngine() {
    return engine;
}

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

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

這個(gè)方法是EngineRunnable類中的情龄,這個(gè)類從名字就可以看出來(lái)它的作用就是響應(yīng)Engine的。而這里的onResourceReady()則是觸發(fā)了GenericRequest中的一個(gè)回調(diào)onResourceReady()

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

這里又調(diào)用了該類中的一個(gè)重載方法:

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

這里我們看到了捍壤,這個(gè)方法使用到了model骤视,而這個(gè)方法則屬于一個(gè)RequestListener回調(diào)接口,這個(gè)回調(diào)接口究竟會(huì)在哪里被調(diào)用呢鹃觉,其實(shí)就是我們上面提到的GlideDrawableImageViewTargetonResourceReady()专酗,而在這個(gè)方法中,另一個(gè)參數(shù)target在這里的實(shí)際類型就是GlideDrawableImageViewTarget盗扇。到這里我們終于是弄明白整個(gè)圖片資源的加載過(guò)程了祷肯。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蒋纬,隨后出現(xiàn)的幾起案子猎荠,更是在濱河造成了極大的恐慌,老刑警劉巖蜀备,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件关摇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碾阁,警方通過(guò)查閱死者的電腦和手機(jī)输虱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脂凶,“玉大人宪睹,你說(shuō)我怎么就攤上這事〔锨眨” “怎么了横堡?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)冠桃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)道宅,這世上最難降的妖魔是什么食听? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮污茵,結(jié)果婚禮上樱报,老公的妹妹穿的比我還像新娘。我一直安慰自己泞当,他們只是感情好迹蛤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著襟士,像睡著了一般盗飒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陋桂,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天逆趣,我揣著相機(jī)與錄音,去河邊找鬼嗜历。 笑死宣渗,一個(gè)胖子當(dāng)著我的面吹牛抖所,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播痕囱,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼田轧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鞍恢?” 一聲冷哼從身側(cè)響起傻粘,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎有序,沒(méi)想到半個(gè)月后抹腿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旭寿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年警绩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盅称。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肩祥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缩膝,到底是詐尸還是另有隱情混狠,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布疾层,位于F島的核電站将饺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痛黎。R本人自食惡果不足惜予弧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望湖饱。 院中可真熱鬧掖蛤,春花似錦、人聲如沸井厌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仅仆。三九已至器赞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墓拜,已是汗流浹背拳魁。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撮弧,地道東北人潘懊。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓姚糊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親授舟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子救恨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一、簡(jiǎn)介 在泰國(guó)舉行的谷歌開發(fā)者論壇上释树,谷歌為我們介紹了一個(gè)名叫Glide的圖片加載庫(kù)肠槽,作者是bumptech。這...
    天天大保建閱讀 7,477評(píng)論 2 28
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,171評(píng)論 25 707
  • 日子過(guò)得太快了奢啥,還停留在學(xué)校的回憶里秸仙,就已經(jīng)畢業(yè)兩年了。 曾經(jīng)那么討厭在學(xué)校桩盲,想要過(guò)自由的日子寂纪,出來(lái)工作上班,一切...
    十里夢(mèng)江南閱讀 216評(píng)論 0 0
  • 大家好,我是大夢(mèng)柬姚。 相信熟悉一周文章的伙伴應(yīng)該都看過(guò)我們系列的手機(jī)攝影推送拟杉。以前愛折騰,推薦過(guò)不少工具也寫了不少技...
    一周青年閱讀 873評(píng)論 0 3
  • 三天前的課到現(xiàn)在剛爬樓聽完量承,可見我的拖延癥非常嚴(yán)重搬设,當(dāng)然,和我的本職工作常常會(huì)打斷我的精力和私人時(shí)間也有很多關(guān)系撕捍。...
    呆萌小青瓜閱讀 656評(píng)論 1 1