Glide系列(五)Glide回調(diào)和監(jiān)聽機制分析

圖片回調(diào)的流程

前面的文章詳細介紹了Glide加載圖片的流程尚蝌,這里我們重點回顧一下圖片的的顯示流程:DecodeJob完成圖片的裝載之后楔绞,會回調(diào)到notifyEncodeAndRelease()方法畦浓,之后的流程如下:


57FA93A3-AEAE-4DF9-8EB2-72CE6BB24196.JPG

上面的流程可以看到遮婶,圖片展示的地方是在Target的onResourceReady()中執(zhí)行的书蚪。這里的Target是哪個步驟構(gòu)建的呢谢肾?回顧一下前面的文章流程中可以知道,在into()方法中钦铺,會構(gòu)建Target订雾,在Request的構(gòu)建中,Target作為參數(shù)傳進Request中矛洞。

自定義Target的原理和實現(xiàn)

上面的圖片回調(diào)流程基本上就介紹了Target的原理洼哎,自定義Target的時候,只需要實現(xiàn)onResourceReady()方法中展示圖片即可缚甩,使用定義Target的用法如下:

SimpleTarget<GlideDrawable> simpleTarget = new SimpleTarget<GlideDrawable>() {
    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
        imageView.setImageDrawable(resource);
    }
};

public void loadImage(View view) {
    String url = "http://cn.bing.com/az/hprichbg/rb/TOAD_ZH-CN7336795473_1920x1080.jpg";
    Glide.with(this)
         .load(url)
         .into(simpleTarget);

以上是基本的自定義Target的用法谱净,掌握了圖片的顯示流程就可以定義復雜的Target窑邦,實現(xiàn)復雜的圖片加載需求擅威。

Preload的功能和原理

preload()可以替換into()法的另外一個方法,和into()不同的是冈钦,preload()方法只加載圖片郊丛,而不顯示圖片,是一種圖片預加載的功能,使真正顯示圖片的時候不需要從網(wǎng)絡獲取厉熟,提高圖片的顯示速度导盅。preload()方法是如何實現(xiàn)不加載圖片的呢?通過前面的圖片加載流程揍瑟,我們知道白翻,獲取圖片之后DecodeJob會執(zhí)行圖片的顯示流程,而圖片顯示是Target完成的绢片。之前的文章分析Glide加載圖片的流程的時候我們知道into()方法滤馍,Glide內(nèi)部邏輯中會構(gòu)建一個Target,這個Target就是顯示圖片的對象底循。我們需要分析preload()內(nèi)部的Target是如何不顯示圖片的巢株。

public Target<TranscodeType> preload() {
    return preload(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
  }
    public Target<TranscodeType> preload(int width, int height) {
    final PreloadTarget<TranscodeType> target = PreloadTarget.obtain(requestManager, width, height);
    return into(target);
  }

我們可以看到:preload()方法會先構(gòu)建一個PreloadTarget對象,然后調(diào)用into(targe)熙涤。所以PreloadTarget類完成了圖片不顯示的邏輯阁苞。我們分析一下PreloadTarget的實現(xiàn):

private static final Handler HANDLER = new Handler(Looper.getMainLooper(), new Callback() {
    @Override
    public boolean handleMessage(Message message) {
      if (message.what == MESSAGE_CLEAR) {
        ((PreloadTarget<?>) message.obj).clear();
        return true;
      }
      return false;
    }
  });


  @Override
  public void onResourceReady(Z resource, Transition<? super Z> transition) {
    HANDLER.obtainMessage(MESSAGE_CLEAR, this).sendToTarget();
  }

可以看到PreloadTarget內(nèi)部在onResourceReady()中僅僅是發(fā)送了一個message,并沒有顯示圖片祠挫。需要注意的是preload()默認是全尺寸緩存圖片的那槽,使用into()顯示preoload()已經(jīng)預加載的圖片時,需要指定緩存策略為DiskCacheStrategy.SOURCE等舔,否則into()會找不到緩存倦炒,從網(wǎng)絡加載圖片。

downloadOnly的功能和原理

into()和preload()方法都是加載圖片的操作软瞎,不提供圖片的路徑信息逢唤,開發(fā)者只關(guān)心圖片顯示的問題,對圖片本身不關(guān)注涤浇,如果我們需要對圖片本身的信息做處理的話鳖藕,就需要知道圖片的保存路徑,Glide提供了兩個方法可以獲取圖片的路徑:

  1. downloadOnly(int width, int height)
  2. downloadOnly(Y target)

downloadOnly(int width, int height)方法只锭,該方法主要完成圖片加載不顯示著恩,與preload功能相似,同時他提供了一個獲取圖片緩存路徑的方法蜻展,該方法是阻塞方法喉誊,如果圖片沒有下載成功,會阻塞纵顾,因此一般使用get()方法需要在子線程中調(diào)用伍茄,同時get()內(nèi)部也會檢查是否在子線程,否則拋異常施逾。
downloadOnly(Y target)不同的是不需要再子線程中運行敷矫。

protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
      new RequestOptions().diskCacheStrategy(DiskCacheStrategy.DATA).priority(Priority.LOW) .skipMemoryCache(true);
 public FutureTarget<File> downloadOnly(int width, int height) {
    return getDownloadOnlyRequest().submit(width, height);
  }
  protected RequestBuilder<File> getDownloadOnlyRequest() {
    return new RequestBuilder<>(File.class,this).apply(DOWNLOAD_ONLY_OPTIONS);
  }
  public FutureTarget<TranscodeType> submit(int width, int height) {
    final RequestFutureTarget<TranscodeType> target =
        new RequestFutureTarget<>(glideContext.getMainHandler(), width, height);

    if (Util.isOnBackgroundThread()) {
      glideContext.getMainHandler().post(new Runnable() {
        @Override
        public void run() {
          if (!target.isCancelled()) {
            into(target, target);
          }
        }
      });
    } else {
      into(target, target);
    }

    return target;
  }

可以看到downloadOnly(int width, int height)內(nèi)部構(gòu)建的Target是RequestFutureTarget例获,圖片的不顯示功能和get()圖片緩存文件都是在這里提供的。

 public synchronized void onResourceReady(R resource, Transition<? super R> transition) {
    // Ignored, synchronized for backwards compatibility.
  }
  public R get() throws InterruptedException, ExecutionException {
    try {
      return doGet(null);
    } catch (TimeoutException e) {
      throw new AssertionError(e);
    }
  }
private synchronized R doGet(Long timeoutMillis)
      throws ExecutionException, InterruptedException, TimeoutException {
    if (assertBackgroundThread && !isDone()) {
      Util.assertBackgroundThread();
    }

    if (isCancelled) {
      throw new CancellationException();
    } else if (loadFailed) {
      throw new ExecutionException(exception);
    } else if (resultReceived) {
      return resource;
    }

    if (timeoutMillis == null) {
      waiter.waitForTimeout(this, 0);
    } else if (timeoutMillis > 0) {
      waiter.waitForTimeout(this, timeoutMillis);
    }

    if (Thread.interrupted()) {
      throw new InterruptedException();
    } else if (loadFailed) {
      throw new GlideExecutionException(exception);
    } else if (isCancelled) {
      throw new CancellationException();
    } else if (!resultReceived) {
      throw new TimeoutException();
    }

    return resource;
  }

RequestFutureTarget的onResourceReady內(nèi)部沒有做任何實現(xiàn)曹仗。而get()方法是個阻塞方法榨汤,如果圖片還沒有加載完成,get()的調(diào)用線程會被阻塞怎茫;同時get()內(nèi)部也做了線程判斷收壕,如果不是在子線程,會拋異常轨蛤。

Listener的功能和原理

listener()方法提供了一個功能:圖片加載的狀態(tài)啼器,加載完成或者加載失敗的結(jié)果。

 boolean onLoadFailed(@Nullable GlideException e, Object model, Target<R> target,
      boolean isFirstResource);
       boolean onResourceReady(R resource, Object model, Target<R> target, DataSource dataSource,
      boolean isFirstResource);

listener方法的參數(shù)RequestListener內(nèi)部有兩個方法

  1. onResourceReady 標識加載成功俱萍,以及圖片資源resource端壳,返回值標識是否處理了結(jié)果
  2. onLoadFailed 表示加載失敗,以及失敗的原因GlideException 枪蘑。返回值標識是否處理了結(jié)果

listener方法的參數(shù)RequestListener损谦,會在構(gòu)建Request的時候,保存在request的屬性requestListener岳颇。
在DecodeJob回調(diào)的流程中會在Request中調(diào)用onResourceReady或者onLoadFailed

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末照捡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子话侧,更是在濱河造成了極大的恐慌栗精,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞻鹏,死亡現(xiàn)場離奇詭異悲立,居然都是意外死亡,警方通過查閱死者的電腦和手機新博,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門薪夕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赫悄,你說我怎么就攤上這事原献。” “怎么了埂淮?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵姑隅,是天一觀的道長。 經(jīng)常有香客問我倔撞,道長讲仰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任误窖,我火速辦了婚禮叮盘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霹俺。我一直安慰自己柔吼,他們只是感情好,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布丙唧。 她就那樣靜靜地躺著愈魏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪想际。 梳的紋絲不亂的頭發(fā)上培漏,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音胡本,去河邊找鬼牌柄。 笑死,一個胖子當著我的面吹牛侧甫,可吹牛的內(nèi)容都是我干的珊佣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼披粟,長吁一口氣:“原來是場噩夢啊……” “哼咒锻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起守屉,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤惑艇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拇泛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滨巴,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年俺叭,在試婚紗的時候發(fā)現(xiàn)自己被綠了兢卵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡绪颖,死狀恐怖秽荤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柠横,我是刑警寧澤窃款,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站牍氛,受9級特大地震影響晨继,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搬俊,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一紊扬、第九天 我趴在偏房一處隱蔽的房頂上張望蜒茄。 院中可真熱鬧,春花似錦餐屎、人聲如沸檀葛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屿聋。三九已至赖阻,卻和暖如春嘱朽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胧弛。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工盘寡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留楚殿,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓竿痰,卻偏偏與公主長得像勒魔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子菇曲,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

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

  • 同讀一本書《溝通的藝術(shù)》 2016-10-19-77 正文:在饑餓或者飽餐的狀況下冠绢,人的表現(xiàn)也會大有不同,研究發(fā)現(xiàn)...
    楊健effort閱讀 941評論 2 0
  • 度滄桑常潮,冷眼看世弟胀,猶嘆夢短。韶韶年華今已去喊式,冉冉斜陽似血殘孵户。山高水長,風流云散岔留。淚撫...
    冰夫閱讀 287評論 0 0
  • 近來耳朵略有不適献联,痛癢難耐竖配,我忍不住用小指頭去掏!掏著掏著里逆,驀地想起一個情景:小時候總愛趴在媽媽的大腿上进胯,一邊臉貼...
    LMClemon閱讀 252評論 0 0
  • [轉(zhuǎn)]暴雪創(chuàng)始人暴雪游戲研發(fā)的10個核心理念 原文鏈接:http://www.gamelook.com.cn/20...
    babybus_break閱讀 1,017評論 0 2