跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(四)

前言

近期研究了一下Glide的圖片加載框架玷或,在這里和大家分享一下通铲。由于代碼研讀有限毕莱,難免有錯(cuò)誤的地方,了解的童鞋還望指正测暗。學(xué)習(xí)小組QQ群: 193765960央串。

本篇是Glide框架及源碼解析的第四篇,更多文章敬請(qǐng)關(guān)注后續(xù)文章碗啄。如果這篇文章對(duì)大家學(xué)習(xí)Glide有幫助质和,還望大家多多轉(zhuǎn)載。

版權(quán)歸作者所有稚字,如有轉(zhuǎn)發(fā)饲宿,請(qǐng)注明文章出處:http://www.reibang.com/u/d43d948bef39

相關(guān)文章:

跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(一)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(二)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(三)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(四)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(五)

在之前的文章中,我們已經(jīng)知道了Glide請(qǐng)求是如何被加載到請(qǐng)求隊(duì)列中并執(zhí)行的胆描,也了解了資源是如何管理的瘫想。本篇文章我們將探究一下資源是如何獲取并分發(fā)的。

資源請(qǐng)求和回調(diào)機(jī)制類(lèi)圖

資源請(qǐng)求和回調(diào)機(jī)制類(lèi)圖

request開(kāi)啟請(qǐng)求

request被加載到requestTracker中統(tǒng)一管理啟動(dòng)獲取資源昌讲,代碼如下:

public void runRequest(Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    pendingRequests.add(request);
  }
}
  • request的執(zhí)行從其begin()方法開(kāi)始:
public void runRequest(Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    pendingRequests.add(request);
  }
}

獲取Engin對(duì)象并封裝任務(wù)

  • 獲取engine對(duì)象国夜,在load()方法中創(chuàng)建EnginJob任務(wù)
  • 為Enginjob創(chuàng)建異步線程EnginRunnable
  • 為EnginRunnable初始化資源獲取解析任務(wù)DecodJob
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) {
 
  Util.assertMainThread();
  long startTime = LogTime.getLogTime();

  final String id = fetcher.getId();
   
  //獲取key
  EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
  loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
  transcoder, loadProvider.getSourceEncoder());
 
  //查找LruResourceCache
  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;
  }
 
  //查找ActiveResourceCache
  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;
  }
 
  //任務(wù)排重
  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);
  }
  
  //創(chuàng)建EngineJob
  EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
   
  //創(chuàng)建DecodeJob:注意fetcher(數(shù)據(jù)加載器)
  DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
  transcoder, diskCacheProvider, diskCacheStrategy, priority);
  
  //創(chuàng)建任務(wù)線程
  EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
  
  //將任務(wù)加入管理隊(duì)列
  jobs.put(key, engineJob);
  engineJob.addCallback(cb);
  
  //啟動(dòng)任務(wù)
  engineJob.start(runnable);

  if (Log.isLoggable(TAG, Log.VERBOSE)) {
    logWithTimeAndKey("Started new load", startTime, key);
  }
  return new LoadStatus(cb, engineJob);
}

執(zhí)行任務(wù)獲取數(shù)據(jù)并解析

  • DecodJob通過(guò)數(shù)據(jù)獲取器DataFetcher獲取數(shù)據(jù)文件(流)
    request被加載到requestTracker中統(tǒng)一管理啟動(dòng)獲取資源,代碼如下:
//EngineRunnable的run()方法
public void run() {
  if (isCancelled) {
    return;
  }

  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 (isCancelled) {
    if (resource != null) {
      resource.recycle();
    }
    return;
  }

  if (resource == null) {
    onLoadFailed(exception);
  } else {
    onLoadComplete(resource);
  }
}
 
 private Resource<?> decode() throws Exception {
   if (isDecodingFromCache()) {
      return decodeFromCache();
   } else {
      return decodeFromSource();
   }
 }
    
 private Resource<?> decodeFromSource() throws Exception {
    return decodeJob.decodeFromSource();
 }
  • 數(shù)據(jù)解析器對(duì)data數(shù)據(jù)解析生成resource資源對(duì)象
private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        //數(shù)據(jù)加載器獲取數(shù)據(jù)
        final A data = fetcher.loadData(priority);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Fetched data", startTime);
        }
        if (isCancelled) {
            return null;
        }
        
        //data數(shù)據(jù)解析生成resource資源對(duì)象
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}
 
//HttpUrlFetcher:網(wǎng)絡(luò)資源加載器
public InputStream loadData(Priority priority) throws Exception {
    return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
  • resource資源進(jìn)一步封裝成為EnginResource對(duì)象
//Runnable的方法短绸,在run()方法中調(diào)用
private void onLoadComplete(Resource resource) {
    manager.onResourceReady(resource);
}
 
//manager.onResourceReady(resource)實(shí)際回調(diào)了Enginjob的接口實(shí)現(xiàn)
public void onResourceReady(final Resource<?> resource) {
  this.resource = resource;
  MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
  • 通過(guò)監(jiān)聽(tīng)接口回傳EnginResource對(duì)象
private void handleResultOnMainThread() {
  if (isCancelled) {
    resource.recycle();
    return;
  } else if (cbs.isEmpty()) {
    throw new IllegalStateException("Received a resource without any callbacks to notify");
  }
  engineResource = engineResourceFactory.build(resource, isCacheable);
  hasResource = true;

  // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
  // synchronously released by one of the callbacks.
  engineResource.acquire();
  listener.onEngineJobComplete(key, engineResource);

  for (ResourceCallback cb : cbs) {
    if (!isInIgnoredCallbacks(cb)) {
      engineResource.acquire();
      //回傳engineResource到request中车吹,request獲取到資源后開(kāi)始刷新UI
      cb.onResourceReady(engineResource);
    }
  }
  // Our request is complete, so we can release the resource.
  engineResource.release();
}

(本篇是Glide框架及源碼解析的第四篇,更多文章敬請(qǐng)關(guān)注后續(xù)文章醋闭。版權(quán)歸作者所有窄驹,如有轉(zhuǎn)發(fā),請(qǐng)注明文章出處:原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末证逻,一起剝皮案震驚了整個(gè)濱河市乐埠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖丈咐,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瑞眼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡扯罐,警方通過(guò)查閱死者的電腦和手機(jī)负拟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)歹河,“玉大人,你說(shuō)我怎么就攤上這事花吟〗掌纾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵衅澈,是天一觀的道長(zhǎng)键菱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)今布,這世上最難降的妖魔是什么经备? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮部默,結(jié)果婚禮上侵蒙,老公的妹妹穿的比我還像新娘。我一直安慰自己傅蹂,他們只是感情好纷闺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著份蝴,像睡著了一般犁功。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婚夫,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天浸卦,我揣著相機(jī)與錄音,去河邊找鬼案糙。 笑死限嫌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的侍筛。 我是一名探鬼主播萤皂,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼匣椰!你這毒婦竟也來(lái)了裆熙?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎入录,沒(méi)想到半個(gè)月后蛤奥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡僚稿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年凡桥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚀同。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缅刽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蠢络,到底是詐尸還是另有隱情衰猛,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布刹孔,位于F島的核電站啡省,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏髓霞。R本人自食惡果不足惜卦睹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望方库。 院中可真熱鬧结序,春花似錦、人聲如沸薪捍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)酪穿。三九已至凳干,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間被济,已是汗流浹背救赐。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留只磷,地道東北人经磅。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像钮追,于是被迫代替她去往敵國(guó)和親预厌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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