美文网首页
Retrofit之知其所以然

Retrofit之知其所以然

作者: jiangweibin | 来源:发表于2018-11-19 21:22 被阅读0次

    知其所以然

    源码分析首先从入口开始,先来回忆Retrofit的使用步骤:

    1.创建Retrofit实例
    2.创建 网络请求接口实例 并 配置网络请求参数
    3.发送网络请求
    4.解析网络请求完成服务器返回的数据

    Retrofit流程

    创建Retrofit实例

    1,Builder设置参数
      Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    

    Retrofit实例是通过建造者模式Builder类进行创建的,Builder类包含以下可以设置参数的方法:

        /**
         *  可提前通过OkHttpClient 设置基本参数类似baseUrl、各种拦截器等
         */
        public Builder client(OkHttpClient client) {
          return callFactory(checkNotNull(client, "client == null"));
        }
    
        /**
         *  网络请求器的工厂
         *  作用:生产网络请求器(Call)
         *  如果没有设置Retrofit是默认使用OkHttpClient
         */
        public Builder callFactory(okhttp3.Call.Factory factory) {
          this.callFactory = checkNotNull(factory, "factory == null");
          return this;
        }
    
        /**
         * Set the API base URL.
         *
         * @see #baseUrl(HttpUrl)
         */
        public Builder baseUrl(String baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          HttpUrl httpUrl = HttpUrl.parse(baseUrl);
          if (httpUrl == null) {
            throw new IllegalArgumentException("Illegal URL: " + baseUrl);
          }
          return baseUrl(httpUrl);
        }
        
        /**
         * 这个细讲
         */
        public Builder baseUrl(HttpUrl baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          List<String> pathSegments = baseUrl.pathSegments();
          if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
            throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
          }
          this.baseUrl = baseUrl;
          return this;
        }
    
        /**
        * 数据转换器工厂的集合
        * 作用:放置数据转换器工厂
        * 数据转换器工厂作用:生产数据转换器(converter)
        */
        public Builder addConverterFactory(Converter.Factory factory) {
          converterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    
        /**
         * 网络请求适配器工厂的集合
         * 作用:放置网络请求适配器工厂
         * 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter) 
         * 如果没有设置默认使     ExecutorCallAdapterFactory
         * 后面在细说
         */
        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    
        /**
         * 方法回调器,可以控制结果返回的线程等
         * 注意: {@code executor} 不是用作 {@linkplain #addCallAdapterFactory 方法的返回类型
         */
        public Builder callbackExecutor(Executor executor) {
          this.callbackExecutor = checkNotNull(executor, "executor == null");
          return this;
        }
    
        /**
         * Retrofit调用 {@link #create}时 , 设置成true这个配置可以提前对业务接口中的注解进行验证转换的标志  
         *位
         */
        public Builder validateEagerly(boolean validateEagerly) {
          this.validateEagerly = validateEagerly;
          return this;
        }
    

    这里我们细讲下baseUrl,其他的后面调用的时候在做分析:Baseurl

    baseUrl的设置还是有点讲究的,我们一般设置一个String类型的字符串,Retrofit会把String转换成符合OKHttp请求的HttpUrl,最好按规矩办事,不然容易出问题:

    1,baseUrl应该以"/"结尾(非强制,但这样设置能避免很多问题)
    2,方法设置的url只如果以“/”开头,默认就是绝对值,同样也可以设置一个完整的Url


    baseUrl不以“/”结尾
    正解: http://example.com/api/ + foo/bar/ = http://example.com/api/foo/bar/
    错误: http://example.com/api + foo/bar/ = http://example.com/foo/bar/;

    HttpUrl会通过各种手段BaseUrl截取最后一个“/”之前的内容作为BaseUrl

    方法设置的url只如果以“/”开头
    BaseUrlL: http://example.com/api/
    方法设置的url: /foo/bar/
    最终请求的完整url:http://example.com/foo/bar/

    BaseUrl: http://example.com/
    方法设置的url:/foo/bar/
    最终请求的完整url:http://example.com/foo/bar/

    如果方法设置的url以“/”开头则被认为是绝对值,最终的而结果是截取掉BaseUrl第一个“/”后面的部分在进行拼接

    方法设置的url如果是个完成的url,baseUrl将不起作用
    BaseUrl: http://example.com/
    方法设置的url:https://github.com/square/retrofit/
    最终请求的完整url:https://github.com/square/retrofit/

    BaseUrl: http://example.com/
    方法设置的url://github.com/square/retrofit/
    最终请求的完整url:http://github.com/square/retrofit/(注意是http开头)

    2,参数设置完成开始build方法

    build方法的源码部分
    build方法会在一些参数没有配置的情况下会创建一个默认的对象

       /**
         * Create the {@link Retrofit} instance using the configured values.
         * <p>
         * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
         * OkHttpClient} will be created and used.
         */
        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
          
          //如果没有自定义okhttp3.Call.Factory则默认使用OkHttpClient,OkHttp请求的关键类
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
          //回调方法执行,处理结果回调线程等,通过platform.defaultCallbackExecutor()默认拿到的是MainThreadExecutor
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
          // 创建防御类型的对象(避免对同一个对象的操作),如果没有设置则默认为ExecutorCallAdapterFactory,如果使用rxjava则需要设置RxJavaCallAdapterFactory
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // 创建防御类型的数据解析对象(避免对同一个对象的操作)
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
    

    在创建执行方法回调callbackExecutor 时用到 platform.defaultCallbackExecutor(),platform是Builder的构造方法里面创建的一个平台对象

    Builder(Platform platform) {
          this.platform = platform;
          // Add the built-in converter factory first. This prevents overriding its behavior but also
          // ensures correct behavior when using converters that consume all types.
          converterFactories.add(new BuiltInConverters());
        }
    
        public Builder() {
          this(Platform.get());
        }
    

    我们一般使用的时候不会去设置platform,因为默认的就是Android平台

    private static final Platform PLATFORM = findPlatform();
    
      static Platform get() {
        return PLATFORM;
      }
    
      //通过findPlatform去寻找默认的平台
      private static Platform findPlatform() {
        try {
          Class.forName("android.os.Build");
          if (Build.VERSION.SDK_INT != 0) {
            //android开发这里是默认的平台
            return new Android();
          }
        } catch (ClassNotFoundException ignored) {
        }
        try {
          Class.forName("java.util.Optional");
          return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        try {
          Class.forName("org.robovm.apple.foundation.NSObject");
          //IOS都支持?
          return new IOS();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
      }
      
      //这里是android平台的实现
      static class Android extends Platform {
         //platform.defaultCallbackExecutor()调用,默认是MainThreadExecutor,这是一个将结果发送到主线程的回调方法执行器,也可以通过自定义处理
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
        
        //如果没有设置对rxjava(RxJavaCallAdapterFactory)的支持这里  默认ExecutorCallAdapterFactory是对Call对象的处理
        @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    
        //通过Looper.getMainLooper()拿到主线程的looper将结果发送到主线程
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    

    Retrofit还可以在其他的平台使用

    平台包括:Android、Rxjava、Guava和java8,需要添加对应的RxJavaCallAdapterFactory,Java8
    CallAdapterFactory等

    2.配置网络请求参数

    Retrofit实例创建之后会调用create方法创建interface对象,在通过接口对象调用相应的方法

    public interface CategoryService {
    
            @GET("top250") 
            Call<MovieEntity> getcategoryList(@Query("start") int start, @Query("count") int count);
            
            @POST("/form")
            @FormUrlEncoded
            Call<ResponseBody> submit(@Field("username") String name, @Field("token") String token);
    }
    
    retrofit.create(CategoryService.class).getcategoryList(0,10);
    
    create方法

    create源码部分

     public <T> T create(final Class<T> service) {
        //检查是否为接口
        Utils.validateServiceInterface(service);
        //如果设置了validateEagerly为true,就会带调用eagerlyValidateMethods对接口中的所有方法进行提前配置
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              //这里还是拿到平台对象,和实例一样用Android平台的对象
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, Object... args)
                  throws Throwable {
                // 如果是来自Object的方法则按调默认的invoke方法
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                //platform.isDefaultMethod 默认返回false,Android没有重写,固为false,java8倒是有重写这个方法
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                //这里就是loadServiceMethod配置ServiceMethod 
                ServiceMethod serviceMethod = loadServiceMethod(method);
                OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                //通过创建的serviceMethod对象里创建的CallAdapter的adapt方法去适配生成相应的网络请求代理 (Call,Obsevalble)
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    
    private void eagerlyValidateMethods(Class<?> service) {
        Platform platform = Platform.get();
        //拿到接口中的所有方法进行配置
        for (Method method : service.getDeclaredMethods()) {
          if (!platform.isDefaultMethod(method)) {
            loadServiceMethod(method);
          }
        }
      }
    
    ServiceMethod loadServiceMethod(Method method) {
        ServiceMethod result;
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            //将参数配置给ServiceMethod
            result = new ServiceMethod.Builder(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    

    create创建相应的接口对象后调用getcategoryList方法会通过InvocationHandler 配置ServiceMethod对象,并通过CallAdapter的adpt方法生成相应的Call或Observable。
    这里主要涉及到ServiceMethod的配置问题需要详细说明

    1,Retrofit的参数传递给ServiceMethod
    2,方法的注解和方法参数的注解解析并复制给ServiceMethod的参数

    so,ServiceMethod包含了网络请求的所有参数成了全村人的希望

    关于ServiceMethod
    public Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
          //拿到方法上面的所有注解
          this.methodAnnotations = method.getAnnotations();
          //拿到方法的所有泛型类型
          this.parameterTypes = method.getGenericParameterTypes();
          //拿到方法参数的所有注解,注意是参数的注解,这是一个二维数组,表示一个参数可以有两个注解,第一个下标志表示所有参数的下标,第二个参数表示一个参数中其中一个注解的下标
          this.parameterAnnotationsArray = method.getParameterAnnotations();
        }
    
    public ServiceMethod build() {
          //创建一个CallAdapter对象最后会调用他的adapt方法创建Call或ObserVable
          callAdapter = createCallAdapter();
          responseType = callAdapter.responseType();
          if (responseType == Response.class || responseType == okhttp3.Response.class) {
            throw methodError("'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
          }
          responseConverter = createResponseConverter();
    
          //解析所有的方法注解并赋值
          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }
          //请求方法不能为空,比如GET,POST必须有一个
          if (httpMethod == null) {
            throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
          }
          
          //如果注解是@GET则@Multipart和@FormEncoded都不能存在
          if (!hasBody) {
            if (isMultipart) {
              throw methodError(
                  "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
            }
            if (isFormEncoded) {
              throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
                  + "request body (e.g., @POST).");
            }
          }
    
          //下面是对参数注解的解析
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0; p < parameterCount; p++) {
            Type parameterType = parameterTypes[p];
            if (Utils.hasUnresolvableType(parameterType)) {
              throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
                  parameterType);
            }
    
            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
            if (parameterAnnotations == null) {
              throw parameterError(p, "No Retrofit annotation found.");
            }
    
            parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
          }
          
          //没有设置url(在方法注解和参数注解都没有设置url)
          if (relativeUrl == null && !gotUrl) {
            throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
          }
    
          //@Body注解的必须同时存在@Multipart或@FormEncoded或POST放等其中一种
          if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
            throw methodError("Non-body HTTP method cannot contain @Body.");
          }
    
          //@FormEncoded注解至少要一个参数注解是@Field
          if (isFormEncoded && !gotField) {
            throw methodError("Form-encoded method must contain at least one @Field.");
          }
          
           //@Multipart注解至少要一个参数注解是@Part
          if (isMultipart && !gotPart) {
            throw methodError("Multipart method must contain at least one @Part.");
          }
    
          return new ServiceMethod<>(this);
        }
    
    
    关于CallAdapter

    ServiceMethod对象生成以后会利用CallAdapter的adapter方法生成Call对象,典型的适配器模式
    CallAdapter的生成在ServiceMethod中

    private CallAdapter<?> createCallAdapter() {
          Type returnType = method.getGenericReturnType();
          //方法的返回类型中泛型不能是T,K等变量或者通配符
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
    
         //void也不行
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
          Annotation[] annotations = method.getAnnotations();
          try {
            return retrofit.callAdapter(returnType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create call adapter for %s", returnType);
          }
        }
      
      public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
      }
      
      public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
        
        拿到第一个null后的值,如果集合中没有null则start 为0
        int start = adapterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
          if (adapter != null) {
            return adapter;
          }
        }
        
        //这里后面操作了一堆只是为了抛一个异常
        StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
            .append(returnType)
            .append(".\n");
        if (skipPast != null) {
          builder.append("  Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append("  Tried:");
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    

    adapterFactories默认是ExecutorCallAdapterFactory,他的get方法

    通过get方法生成CallAdapter
    @Override
      public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
          
          //最后通过adapt方法创建Call<R> 的实现类ExecutorCallbackCall
          @Override public <R> Call<R> adapt(Call<R> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    

    创建的CallAdapter调用adapt方法创建了Call的ExecutorCallbackCall实现类

    3.发送网络请求并处理结果

    Call call = retrofit.create(CategoryService.class).getcategoryList(0,10);
    
     call.enqueue(new Callback<MovieEntity>() {
            @Override
            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
                resultTV.setText(response.body().toString());
            }
    
            @Override
            public void onFailure(Call<MovieEntity> call, Throwable t) {
                resultTV.setText(t.getMessage());
            }
        });
    

    这里的call实际是Call的实现类ExecutorCallbackCall,ExecutorCallbackCall的源码

       static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;
        final Call<T> delegate;
        
        //这里参数传进来的是MainThreadExecutor,和OkHttpCall对象
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
          this.callbackExecutor = callbackExecutor;
          this.delegate = delegate;
        }
        
        //当调用enqueue方法时
        @Override public void enqueue(final Callback<T> callback) {
          if (callback == null) throw new NullPointerException("callback == null");
          代理类OkHttpCall调用enqueue
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
             //这里是将结果发送到主线程
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  if (delegate.isCanceled()) {
                    // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                  } else {
                    callback.onResponse(ExecutorCallbackCall.this, response);
                  }
                }
              });
            }
    
            @Override public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);
                }
              });
            }
          });
        }
    
        @Override public boolean isExecuted() {
          return delegate.isExecuted();
        }
    
        @Override public Response<T> execute() throws IOException {
          return delegate.execute();
        }
    
        @Override public void cancel() {
          delegate.cancel();
        }
    
        @Override public boolean isCanceled() {
          return delegate.isCanceled();
        }
    
        @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
        @Override public Call<T> clone() {
          return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
        }
    
        @Override public Request request() {
          return delegate.request();
        }
      }
    

    代理模式一层套一层
    关于OkHttpCall 的enqueue方法源码

    @Override public void enqueue(final Callback<T> callback) {
        if (callback == null) throw new NullPointerException("callback == null");
        
        okhttp3.Call call;
        Throwable failure;
        
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          call = rawCall;
          failure = creationFailure;
          if (call == null && failure == null) {
            try {
             //关键部分创建okhttp3.Call
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
    
        if (canceled) {
          call.cancel();
        }
        
        //这里就最终和进入到Okhttp的调用流程
        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
              throws IOException {
            Response<T> response;
            try {
              //解析数据
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            callSuccess(response);
          }
          
          @Override public void onFailure(okhttp3.Call call, IOException e) {
            try {
              //回调
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callSuccess(Response<T> response) {
            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    

    createRawCall是关键的创建 okhttp3.Call对象的方法

     private okhttp3.Call createRawCall() throws IOException {
        //把serviceMethod中所有的参数都赋值给Request,毕竟 Request才是OkHttp想要的
        Request request = serviceMethod.toRequest(args);
        //这里serviceMethod.callFactory是oKHttpClient,后面newCall就是OkHttp创建okhttp3.Call 的方法了
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    

    相关文章

      网友评论

          本文标题:Retrofit之知其所以然

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