Gilde(三)图片请求执行过程--into()

Glide 的请求执行过程

  • 要了解请求执行过程首先我们需要知道如下问题
    1. 何时构建的请求
    2. 何时执行的请求
    3. 如何构建的请求
    4. 执行请求

1.请求执行时机&2.请求构建时机

  • 在源码流程分析里我们提到调用into()开始执行图片请求

     public <Y extends Target<TranscodeType>> Y into(Y target) {
            //省略部分代码
         	//1. 获取之前的请求
            Request previous = target.getRequest();
    		//2.判断之前的请求是否为空 
            if (previous != null) {
                previous.clear();
                //将其从追踪器移除方便追踪器追踪下面最新的request
                requestTracker.removeRequest(previous);
                //内部调用 REQUEST_POOL.offer(this);方法,将请求放入请求池以供复用
                previous.recycle();
            }
    		// 3.根据target 生成 request 
            Request request = buildRequest(target);
         	// 4.内部调用了setTag方法给view这只TAG,防止列表图片错乱
            target.setRequest(request);
         	//5.给lifecycle 添加回调(target实现了LifeCycleListener接口)
         	// 这里的lifeCycle就是RequestManagerFragment(无界面fragemnt)里的lifeCycle
            lifecycle.addListener(target);
         	// 6 请求追踪器运行request
            requestTracker.runRequest(request);
            return target;
        }
    
  • 根据上面的代码我们可以得到上面1,2 的答案

    • 在调用into方法的时候先去构建请求,再去执行请求

3.如何构建请求

  • 根据上面代码可知在调用buildRequest(target);的时候构建了请求

        private Request buildRequest(Target<TranscodeType> target) {
            if (priority == null) {
                priority = Priority.NORMAL;
            }
            return buildRequestRecursive(target, null);
        }
    	// 1 可以看到调用buildRequestRecursive(target, null)
    	 private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
            //部分代码  判断是否设置缩略图以及缩略图比例
            //最终都会执行obtainRequest方法
            return obtainRequest方法(target, sizeMultiplier, priority, parentCoordinator);
        }
    	//2 该方法最终执行到GenericRequest
    public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(//参数列表){
            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(//参数列表);
            return request;
        }
        // 3 调用了init 方法生成request
            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;
           }
          // 可以看到  init 方法里就是一些设置属性的初始化操作 就这样构建完了request
    
    
    • 通过GenericRequest的init方法 设置属性 完成request的初始化

4.执行请求

  • 上文我们知通过请求追踪器来执行request

     requestTracker.runRequest(request);
    

requestTracker是什么?

  • 定义

    • 用于跟踪、取消和重新启动正在进行、已完成和失败的请求的类。(请求追踪器)

    • 内部维护两个集合

      • // requests正在执行的请求队列,保证不被使用的request被回收
        Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>())
         //尚未完成的等待排队请求的队列
        List<Request> pendingRequests = new ArrayList<Request>();
        

执行过程

  • runRequest
 /**
     * 开始追踪请求
     */
    public void runRequest(Request request) {
        requests.add(request);
        // 判断当前请求是否暂停 不是则执行begin
        if (!isPaused) {
            request.begin();
        } else {
            // 请求暂停则加入等待队列  根据绑定的声明周期来判断是否处于暂停状态 onstart 开始执行 onStop暂停执行
            pendingRequests.add(request);
        }
    }
  • begin 方法
 public void begin() {
        //1.判断是否调用了override指定宽高
        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            //2.若指定宽高则直接使用该宽高加载图片 重点 onSizeReady
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            //3. 若未指定宽高则根据绘制结果测量宽高,最终还是调用onSizeReady 
            //这里的this 就是SizeReadyCallback的实现onSizeReady
            target.getSize(this);
        }
        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            // 4 读取默认图并设置给target
            target.onLoadStarted(getPlaceholderDrawable());
        }
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
    }
  • getSize方法

    • public void getSize(SizeReadyCallback cb) {
                 int currentWidth = getViewWidthOrParam();
                 int currentHeight = getViewHeightOrParam();
          		// 如果已经完成绘制且宽高有效则调用 onSizeReady
                 if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
                     cb.onSizeReady(currentWidth, currentHeight);
                 } else {
                     if (!cbs.contains(cb)) {
                         cbs.add(cb);
                     }
                     // 如果绘制没结束则加入观察者
                     if (layoutListener == null) {
                         final ViewTreeObserver observer = view.getViewTreeObserver();
                         layoutListener = new SizeDeterminerLayoutListener(this);
                         observer.addOnPreDrawListener(layoutListener);
                     }
                 }
             }
       
      
    • 可以看到最终都调用onSizeReady

      • 设置了override 指定宽高的的直接调用
      • 未指定宽高的 则根据测量结果获取宽高后调用
  • onSizeReady

    • public void onSizeReady(int width, int height) {
          //省略部分代码
          width = Math.round(sizeMultiplier * width);
          height = Math.round(sizeMultiplier * height);
          //1. 获取modelloader
          ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
          //2。通过modelloader获取DataFetcher 
          final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
          //3. 获取转码器
          ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
          loadedFromMemoryCache = true;
          // 4. 调用engine.load完成真正的图片加载
          loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                  priority, isMemoryCacheable, diskCacheStrategy, this);
          loadedFromMemoryCache = resource != null;
      	//省略部分代码
      }
      
      • ModelLoader
        • 一个工厂接口,用于将任意复杂的数据模型转换为原始数据类型 (传递String,url则对应就是io输入流inputstream),从而能够使用DataFetcher去获取由该模型表示的资源的数据。
      • DataFetcher
        • 一个接口,具有多个实现类都代表从指定数据源加载数据,通过ModelLoader创建
        • 比如我们传递Sting 类型urlDataFetcher 对应的实现类为HttpUrlFetcher从url获取资源也就是网络请求
      • ResourceTranscoder
        • 将一种类型的资源转码为另一种类型的资源。
        • 比如BitmapDrawableTranscoder将Bitmap转码为BitmapDrawable
      • engine.load
        • 真正加载图片的地方
    • engine.load

      •     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();        //获取id字符转 加载图片的唯一标识        final String id = fetcher.getId();        //生成缓存的key 重写equals hash 算法生成        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),                transcoder, loadProvider.getSourceEncoder());        //根据key 获取 缓存        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);        //此时得到缓存 若不为空则调用ResourceCallback.onResourceReady 将缓存回调出去        if (cached != null) {            cb.onResourceReady(cached);            if (Log.isLoggable(TAG, Log.VERBOSE)) {                logWithTimeAndKey("Loaded resource from cache", startTime, key);            }            return null;        }        // 从弱引用缓存中获取        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);        // 不为空        if (active != null) {            // 调用onResourceReady 给target 设置图片            cb.onResourceReady(active);            if (Log.isLoggable(TAG, Log.VERBOSE)) {                logWithTimeAndKey("Loaded resource from active resources", startTime, key);            }            return null;        }        // 若缓存中没有则开启新线程 创建 EngineJob 来从磁盘或者网络里加载        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);        }		// 若内存缓存 和 弱引用缓存获取不到则开启线程创建EngineRunnable 去磁盘或者网络加载执行逻辑也就在EngineRunnable的run方法中        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);        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);        return new LoadStatus(cb, engineJob);    }	
        
    • 向下执行到EngineRunnablerun方法

      • public void run() {    // ......   	  resource = decode();   // ......     if (resource == null) {         onLoadFailed(exception);     } else {         onLoadComplete(resource);     } }   	 //decode   	 private Resource<?> decode() throws Exception {      //磁盘缓存默认为auto 根据图片大小和数量来决定是否磁盘缓存     if (isDecodingFromCache()) {         // 从磁盘读取并解码         return decodeFromCache();     } else {         //从网络读取并解码         return decodeFromSource();     } }
        
      • 当获取成功后调用onLoadComplete失败调用onLoadFailed

      • private void onLoadComplete(Resource resource) {    //这里的manager 就是EngineJob    manager.onResourceReady(resource);}
        
      • 通过调用onResourceReady来传递资源

      • @Overridepublic void onResourceReady(final Resource<?> resource) {    this.resource = resource;    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();}
        
      • 可以看到通过handle发送了一个message

        • Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
          
        • 上面是Handler 创建可以看到传递了MainThreadCallback

        • 该CallBack 就是处理返回结果的地方

      • private static class MainThreadCallback implements Handler.Callback {        @Override       public boolean handleMessage(Message message) {           if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {               EngineJob job = (EngineJob) message.obj;               if (MSG_COMPLETE == message.what) {                   // 处理主线程任务                   job.handleResultOnMainThread();               } else {                   //处理主线程异常                   job.handleExceptionOnMainThread();               }               return true;           }            return false;       }   }
        
      • 处理主线程任务

      • private void handleResultOnMainThread() {       //....       engineResource = engineResourceFactory.build(resource, isCacheable);       hasResource = true;    	//若有一个listener 引用则不是放,引用次数+1 放到弱引用缓存中       engineResource.acquire();       listener.onEngineJobComplete(key, engineResource);        for (ResourceCallback cb : cbs) {           if (!isInIgnoredCallbacks(cb)) {               engineResource.acquire();               //调用回调 返回 图片resource               cb.onResourceReady(engineResource);           }       }       // 此时 我们的请求已完成,因此我们可以释放资源。若引用次数为0 则从弱引用缓存队列移除并添加到内存缓存中       engineResource.release();   }
        
      • onResourceReady

      • public void onResourceReady(Resource<?> resource) {    onResourceReady(resource, (R) received);}private void onResourceReady(Resource<?> resource, R result) {    //调用targrt的onResourceReady     target.onResourceReady(result, animation);}//我们以imageviewTargt为例子 @Overridepublic void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {    //设置图片资源 以BitmapImageViewTarget 为例子    setResource(resource);  }//BitmapImageViewTargetpublic class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {    public BitmapImageViewTarget(ImageView view) {        super(view);    }    protected void setResource(Bitmap resource) {        // 设置图片资源        view.setImageBitmap(resource);    }}
        
      • 至此图片加载完成

执行过程总结
  1. 通过requesttracker 执行request 加入set集合,判断是否在执行 若在执行则调用begin,否则加入等待集合
  2. 调用begin,计算target宽高,调用onSizeReady
  3. onSizeReady里 获取ModelLoader,DataFetcher,ResourceTranscoder,调用engine.load 执行真正的加载过程
  4. 在engine.load方法中
    • 先从内存缓存获取,若不存在则从弱引用缓存获取,通过onResourceReady回调将资源设置给target
    • 若二者都不存在则创建EngineRunnable从磁盘或者网络获取,获取到之后通过handler转换到主线程,再通过onResourceReady回调将资源设置给target

  • 综上可知真正的图片加载执行过程是在engine.load里
    • 在这个load 里面涉及到了内存缓存和磁盘缓存以及网络请求获取图片数据所以后面和缓存部分一起说
    • 本文不涉及网络请求相关和缓存相关,后面请看缓存相关
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值