美文网首页Android App架构
跟着源码学设计:Glide框架及源码解析(四)

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

作者: 肖丹晨 | 来源:发表于2017-10-20 12:41 被阅读34次

    前言

    近期研究了一下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框架及源码解析的第四篇,更多文章敬请关注后续文章。版权归作者所有,如有转发,请注明文章出处:原文链接

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/sotvuxtx.html