Gllide源码解析1 -- Requset请求的创建到发送的全过程

一 Glide整体流程图

在这里插入图片描述
Glide源码非常复杂,如果不带目的的去看源码,我相信很快你就晕了,我建议还是带问题的去看源码比较容易的,不然你很容易迷糊的

二 Requset的创建和发送

问题:Glide的那些图片请求都去了那里?
我们先来看一下Glide的简单使用:

RequestManager resquestManager = Glide.with(this);
    DrawableTypeRequest<Integer> drawableTypeRequest = resquestManager.load(R.drawable.ic_launcher_background);
    Target<GlideDrawable> into = drawableTypeRequest.placeholder(R.drawable.test)into(imageView);

2.1 核心类

  1. RequestManager:进行requests随Activity或Fragment生命周期管理,这个是Glide强大功能之一,可以避免内存损耗和泄露
  2. GenericRequestBuilder:使用建造者模式创建Request,其中的into()方法比较关键;针对不同格式的图片,Glide分别做了它们的request builder的实现。
  3. GenericRequest:实现了Request接口,包含request状态和request操作API,如begin(), cancel(), clear(), pause()。 同时它实现了ResourceCallback接口,在获取图片数据exception时回调
  4. RequestTracker:这个是request的管理类,主要包含有两个集合,一个是requests,用来存储正在执行的request;一个是pendingRequests,用来存储处于暂停等待的request
  5. Target:图片的目标实体,相当于MVC中的View。可以简单的理解为对View的适配,Glide在加载完图片的时候,可以通过回调来监听图片加载的情况或者直接对View进行图片的设置,主要的实现类有SimpleTarget,ViewTarget

2.2 源码剖析

首先我们通过with()方法获得一个RequestManager 对象,这个我们先不看,里面代码太多,而且没有我们要找的request请求,我们直接看into()方法:
drawableTypeRequest:

   @Override
    public Target<GlideDrawable> into(ImageView view) {
    
    
        return super.into(view);
    }

GenericRequestBuilder:

//相信大家在看源码的时候经常能看到Target这个类,这里大家可以理解为Glide对传入的View的一次封装,同时添加了LifecycleListener生命周期回调
 public Target<TranscodeType> into(ImageView view) {
    
    
 	  // 主线程判断,对View修改只能在主线程中
        Util.assertMainThread();
        if (view == null) {
    
    
            throw new IllegalArgumentException("You must pass in a non null View");
        }

        if (!isTransformationSet && view.getScaleType() != null) {
    
    
            switch (view.getScaleType()) {
    
    
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }
         //这里把imageview封装成ImageViewTarget,继续调用into()方法
        return into(glide.buildImageViewTarget(view, transcodeClass));
    }


public <Y extends Target<TranscodeType>> Y into(Y target) {
    
    
        Util.assertMainThread();
        if (target == null) {
    
    
            throw new IllegalArgumentException("You must pass in a non null Target");
        }
        if (!isModelSet) {
    
    
            throw new IllegalArgumentException("You must first set a model (try #load())");
        }

        Request previous = target.getRequest();
   // 此ViewTarget如果已经有request,则删除掉它,并从requestTracker集合中remove掉
        if (previous != null) {
    
    
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }
 // 创建Request,典型的builder模式调用。buildRequest()最后调用到obtainRequest(),这个方法会将Glide设置的参数都封装进去
        Request request = buildRequest(target);
        target.setRequest(request);
          // target实现了lifecycleListener,故将它加入到lifecycle,这样在恰当的时机得到回调
        lifecycle.addListener(target);
         // 加入到requestTracker中,并run。它是数据获取的入口,后面重点分析
        requestTracker.runRequest(request);

        return target;
    }


我们来看一下buildRequest()这个方法是如何对Request进行初始化的:

 // buildRequest最终调用到obtainRequest方法,创建Request的关键方法,
    // 将builder中的参数传入,这种方式传入参数太多,个人觉得不优雅,可以创建一个RequestParams数据类来存放参数
GenericRequestBuilderprivate Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
            RequestCoordinator requestCoordinator) {
    
    
        // 看到这么一大段是不是觉得很懵逼了,我也觉得这是Glide写的挺不优雅的一个地方
        return GenericRequest.obtain(
                loadProvider,
                model,
                signature,
                context,
                priority,
                target,
                sizeMultiplier,
                placeholderDrawable,
                placeholderId,
                errorPlaceholder,
                errorId,
                fallbackDrawable,
                fallbackResource,
                requestListener,
                requestCoordinator,
                glide.getEngine(),
                transformation,
                transcodeClass,
                isCacheable,
                animationFactory,
                overrideWidth,
                overrideHeight,
                diskCacheStrategy);
    }


//继续来看一下GenericRequest.obtain()方法
GenericRequest// GenericRequest类,builder中传入的参数最终大部分设到了Request数据类中
public final class GenericRequest<A, T, Z, R> {
    
    

   //参数太多,用args[]表示
 public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(args[]) {
    
    
        @SuppressWarnings("unchecked")
        GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
        if (request == null) {
    
    
            request = new GenericRequest<A, T, Z, R>();
        }
        //这里通过init()方法一次给GenericRequest的参数赋值
        request.init(args[]);
        return request;
    }
}


Ok,到这里我们终于创建了我们熟悉的request了,我们直接来看runRequest()这个方法:

RequestTracker:

public void runRequest(Request request) {
    
    
 // 添加到全部request所在集合中
    requests.add(request);
    if (!isPaused) {
    
    
      // begin()方法是request发送的入口,下面重点介绍
        request.begin();
    } else {
    
    
      // 如果当前状态为paused,则不直接运行,而是添加到等待集合中。这一般发生在Activity或Fragment onStop()时
        pendingRequests.add(request);
    }
}

这段代码很简单,我们应该很容易猜出来,这里应该是根据Glide请求的状态来判断是否执行这个请求,其次这里出现了两个队列requests和pendingRequests,很显然,根据if (!isPaused)这个if判断,我们也知道这两个队列的用途,requests是用来存储正在运行的请求,pendingRequests则是用来存储等待或者未完成的请求

我们来看一下GenericRequest的begin()方法:
GenericRequest :

  public void begin() {
    
    
        // 记录时间
        startTime = LogTime.getLogTime();
        if (model == null) {
    
    
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        // 验证width和height是否合法
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    
    
            // 发送request的关键所在,当获取了width height之后就可以向底层发送request请求了。后面详细说
            onSizeReady(overrideWidth, overrideHeight);
        } else {
    
    
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
    
    
            // 数据load开始前,回调onLoadStarted,一般此时viewTarget会设置placeHolder
            // 这是placeHolder占位图的实现原理,是不是顿时茅厕顿开了呀,哈哈~
            target.onLoadStarted(getPlaceholderDrawable());
        }
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
    
    
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
    }
public void onSizeReady(int width, int height) {
    
    
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
    
    
            logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
        if (status != Status.WAITING_FOR_SIZE) {
    
    
            return;
        }
        // 状态切换
        status = Status.RUNNING;

        // 部分代码省略

        // 采用engine来load数据,此处是最终request发送所在。涉及到cache等很多内容,后面一篇文章再详细分析
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
    
    
            logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
    }
}

// ImageViewTarget类,再回过头看看placeHolder是如何被设到ImageView里面的
public abstract class ImageViewTarget {
    
    
    public void onLoadStarted(Drawable placeholder) {
    
    
        // onLoadStarted中设置placeHolder到ImageView中,也就是占位符设置
        view.setImageDrawable(placeholder);
    }
}

into()方法是比较关键也比较麻烦的一个方法。Glide将View封装为了ViewTarget。into()方法分为request创建和request发送两大部分。创建采用Builder(GenericRequestBuilder)模式生成GenericRequest对象,发送则调用GenericRequest的begin方法,最终回调到底层Engine部分的相关方法。可以看出,经过Glide的层层封装,复杂的逻辑变得相对简单了很多。

猜你喜欢

转载自blog.csdn.net/qq_39431405/article/details/121359055