跟着源码学设计:Glide框架及源码解析(四)

前言

近期研究了一下Glide的图片加载框架,在这里和大家分享一下。由于代码研读有限,难免有错误的地方,了解的童鞋还望指正。学习小组QQ群: 193765960。

本篇是Glide框架及源码解析的第四篇,更多文章敬请关注后续文章。如果这篇文章对大家学习Glide有帮助,还望大家多多转载。

版权归作者所有,如有转发,请注明文章出处:http://www.jianshu.com/u/d43d948bef39

相关文章:

跟着源码学设计:Glide框架及源码解析(一)
跟着源码学设计:Glide框架及源码解析(二)
跟着源码学设计:Glide框架及源码解析(三)
跟着源码学设计:Glide框架及源码解析(四)
跟着源码学设计:Glide框架及源码解析(五)

在之前的文章中,我们已经知道了Glide请求是如何被加载到请求队列中并执行的,也了解了资源是如何管理的。本篇文章我们将探究一下资源是如何获取并分发的。

资源请求和回调机制类图

资源请求和回调机制类图

request开启请求

request被加载到requestTracker中统一管理启动获取资源,代码如下:

public void runRequest(Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    pendingRequests.add(request);
  }
}
  • request的执行从其begin()方法开始:
public void runRequest(Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    pendingRequests.add(request);
  }
}

获取Engin对象并封装任务

  • 获取engine对象,在load()方法中创建EnginJob任务
  • 为Enginjob创建异步线程EnginRunnable
  • 为EnginRunnable初始化资源获取解析任务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;
  }
 
  //任务排重
  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 engineJob = engineJobFactory.build(key, isMemoryCacheable);
   
  //创建DecodeJob:注意fetcher(数据加载器)
  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);

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

执行任务获取数据并解析

  • DecodJob通过数据获取器DataFetcher获取数据文件(流)
    request被加载到requestTracker中统一管理启动获取资源,代码如下:
//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();
 }
  • 数据解析器对data数据解析生成resource资源对象
private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        //数据加载器获取数据
        final A data = fetcher.loadData(priority);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Fetched data", startTime);
        }
        if (isCancelled) {
            return null;
        }
        
        //data数据解析生成resource资源对象
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}
 
//HttpUrlFetcher:网络资源加载器
public InputStream loadData(Priority priority) throws Exception {
    return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
  • resource资源进一步封装成为EnginResource对象
//Runnable的方法,在run()方法中调用
private void onLoadComplete(Resource resource) {
    manager.onResourceReady(resource);
}
 
//manager.onResourceReady(resource)实际回调了Enginjob的接口实现
public void onResourceReady(final Resource<?> resource) {
  this.resource = resource;
  MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
  • 通过监听接口回传EnginResource对象
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获取到资源后开始刷新UI
      cb.onResourceReady(engineResource);
    }
  }
  // Our request is complete, so we can release the resource.
  engineResource.release();
}

(本篇是Glide框架及源码解析的第四篇,更多文章敬请关注后续文章。版权归作者所有,如有转发,请注明文章出处:原文链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容