美文网首页
Retrofit源码笔记

Retrofit源码笔记

作者: 无为3 | 来源:发表于2018-04-08 18:07 被阅读0次

    Retrofit整个流程

    不是网络请求框架,只是对网络框架的封装,底层还是通过okhttp实现
    Retrofit--->ServiceMethod(CallFactory,CallAdapterFactory,ConverterFactory)--->OkHttpCall--->CallAdapter--->Convert--->callbackExecutor)

    1.首先创建Retrofit类,这是Retrofit框架的整个的门面类,是个入口,可以对网络参数进行配置,通过build模式;在创建build时,内部有一个非常重要的类,ServiceMethod类。
    2.ServiceMethod对应我们应用程序中自己写好的接口类中的一个方法;我们会通过动态代理模式将我们定义好的接口中的一些参数,方法最终转换成一个个的http请求;并且负责解析我们方法中的注解,生成我们需要的request对象;并生成了三个非常重要的工厂类:CallAdapter工厂(生产calladapter,而calladapter是我们网络请求Call的适配器,retrofit默认情况下Call是okhttpCall,CallAdapter的作用就是将我们的okhttpCall转换成适应不同平台的的模式),Convert工厂(生成我们的数据转换器Convert,用它将我们网络返回的response转换成我们能使用的java对象,默认是Gson);Call工厂(创建call请求类,一个个的http请求会被抽象封装成Call类,Call工厂就是用来创建http请求)。通过ServiceMethod创建出我们的OkHttpCall

    Retrofit请求过程7步骤
    1.配置依赖库
    2.编写返回数据bean类
    3.创建用于描述网络请求的接口:
    创建一个用于描述我们整个网络请求的接口,retrofit将我们每一个http请求抽象成了java接口,同时通过注解方式描述我们网络请求参数和配置我们整个网络请求参数,
    通过动态代理模式将我们整个接口的注解翻译成了一个http请求。接口中每个方法参数都必须使用注解参数,否则会报错
    4.创建retrofit实例。通过构造者模式,配置baseurl,convertFactory,CallAdapterFactory(RxJava,java8...)等
    5.创建网络接口实例:retrofit.create();
    6.发送网络请求
    7.处理服务器返回的数据

    代理模式:为其他对象提供一种代理,用以控制对这个对象的访问
    静态代理:代理类和被代理类都实现同一个接口,代理类包含被代理类的引用

    动态代理
    代理类在程序运行时创建的代理方式;相比静态代理,可以很方便的对代理类进行统一的处理。有两种动态代理方式
    1).jdk动态代理:需要客户端写辅助类接口;代理类需要实现接口;比较高效
    2).CGLIB:直接修改字节码
    InvocationHandler:
    每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接口的实现。
    invoke方法的参数可以获取参数
    invoke方法的返回值被返回给使用者

    retrofit网络通信流程&步骤
    1).创建retrofit实例
    2).定义一个网络请求接口并为接口中的方法添加注解
    3).通过动态代理生成网络请求对象
    4).通过网络请求适配器将网络请求对象进行平台适配
    5).通过网络请求执行器(Call)发送网络请求
    6).通过数据转换器解析数据
    7).通过回调执行器切换线程
    8).用户在主线程处理结果

    Retrofit类简介:

    使用

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
    MyInterface myInterface = retrofit.creat(MyInterface.class);
    Call call = myInterface.getCall();
    call.enqueue(new retrofit2.Callback(){...});
    

    Retrofit 类源码分析

    /**
    key值是Method,也就是我们http请求方法,ServiceMethod也就是我们接口中的方法及注解,解析后得到的对象;
    serviceMethodCache 主要是适用于缓存的:例如存储网络请求的一些配置,还有网络请求的方法,数据转换器,网络请求
    适配器等等
    **/
    private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
    /**
    callFactory 网络请求的okhttp的工厂,默认生产okhttpclient
    **/
    final okhttp3.Call.Factory callFactory;
    /**
    网络请求的基地址
    **/
    final HttpUrl baseUrl;
    /**
    数据转换器工厂的集合
    **/
    final List<Converter.Factory> converterFactories;
    
    /**
    *网络请求适配器集合,例如将Call转换成Rxjava支持的Call
    **/
    final List<CallAdapter.Factory> adapterFactories;
    
    /**
    *用于执行回调,默认MainThreadExecutor
    **/
    final Executor callbackExecutor;
    
    /**
     *标志位,是否需要立即解析接口中的方法
    **/
    final boolean validateEagerly;
    

    Retrofit.Builder类

    public static final class Builder {
    /**
     *适配的平台,Android,IOS,JAVA8
    **/
        private final Platform platform;
        private okhttp3.Call.Factory callFactory;
        private HttpUrl baseUrl;
        private final List<Converter.Factory> converterFactories = new ArrayList<>();
        private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
        private Executor callbackExecutor;
        private boolean validateEagerly;
        public Builder() {
          this(Platform.get());
        }
    
        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
    
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
    //默认的是okhttpclient
            callFactory = new OkHttpClient();
          }
    
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
    //android平台下返回MainThreadExecutor,具体见下面platform代码
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
          // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    //添加平台支持的默认转换器工厂
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }  
    }
    
    
    /**
    * 支持的平台
    **/
    class Platform {
      private static final Platform PLATFORM = findPlatform();
      static Platform get() {
        return PLATFORM;
      }
      private static Platform findPlatform() {
        try {
          Class.forName("android.os.Build");
          if (Build.VERSION.SDK_INT != 0) {
            return new Android();
          }
        } catch (ClassNotFoundException ignored) {
        }
        try {
          Class.forName("java.util.Optional");
          return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
      }
    /**
    *支持的android平台
    **/
    static class Android extends Platform {
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    //默认的回调执行
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    }
    
    
    RxJava2CallAdapterFactory内部构造与工作原理

    CallAdapter作用就是把我们Retrofit中的Call泛型对象转换成java对象,通过这个java对象来进行别的操作(UI的显示,后台的数据运作等等)。Call<T>--->网络请求--->converter--->java对象,retrofit中的Call是对okhttp中的Call进行了封装

    public interface CallAdapter<R, T> {
      /**用于http请求返回解析后的类型
       */
      Type responseType();
    
      /** T是转换成接口的返回类型(如果是Rxjava,T则为接口中的Observable或者Flowable);参数Call就是okhttpCall的一个对象实例
       **/
      T adapt(Call<R> call);
    
      /** 例如Rxjava2CallAdapterFactory需要继承这个Factory,并添加到Retrofit中集合中
       * Creates {@link CallAdapter} instances based on the return type of {@linkplain
       * Retrofit#create(Class) the service interface} methods.
       */
      abstract class Factory {
        /**根据接口的返回类型注解类型来得到实际需要的Adapter
         * Returns a call adapter for interface methods that return {@code returnType}, or null if it
         * cannot be handled by this factory.
         */
        public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
            Retrofit retrofit);
    
        /**
         * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
         * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
         */
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
          return Utils.getParameterUpperBound(index, type);
        }
    
        /**获取我们原始的类型
         * Extract the raw class type from {@code type}. For example, the type representing
         * {@code List<? extends Runnable>} returns {@code List.class}.
         */
        protected static Class<?> getRawType(Type type) {
          return Utils.getRawType(type);
        }
      }
    }
    
    RxJava2CallAdapterFactory源码解析

    实现CallAdapter.Factory抽象类--->注册CallAdatper(retrofit中addCallAdapterFactory)--->CallAdapter.Factory.get()来进行获取CallAdapter--->adapt()方法将Call转换成每一个平台使用的类型

    public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
     
    
      @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //Factory中的getRawType();返回原始的数据类型;之后一串代码都是判断rawType是否是Rxjava支持的类型;最终会返
    回我们一个CallAdapter的具体实现对象,然后调用adapt来进行Call请求的转换
        Class<?> rawType = getRawType(returnType);
         .......
        return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
            isSingle, isMaybe, false);
      }
    
    /**
    * 举个栗子:RxJava2CallAdapter中对Call转换成Observable
    **/
    final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
    
    @Override public Object adapt(Call<R> call) {
        Observable<Response<R>> responseObservable = isAsync
            ? new CallEnqueueObservable<>(call)
            : new CallExecuteObservable<>(call);
    
        Observable<?> observable;
       ......
        return observable;
      }
    }
    
    Retrofit网络请求接口实例解析

    还是按之前使用的例子来看

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
    //使用动态代理生成接口的代理类
    MyInterface myInterface = retrofit.creat(MyInterface.class);
    /**代理类调用Proxy.newProxyInstance()方法去进行拦截,调用InvocationHandler中的
    invoke方法来进行实际的操作,返回CallAdapter转换okhttpCall后的适应不同平台的网络请求
    本例子中返回的是Call对象,如果支持Rxjava可能返回Flowable等
    **/
    Call call = myInterface.getCall();
    call.enqueue(new retrofit2.Callback(){...});
    

    在初始化Retrofit之后,调用retrofit.create();来看下create中的方法

      public <T> T create(final Class<T> service) {
    //对接口的字节码进行验证
        Utils.validateServiceInterface(service);
    //validateEagerly标志位,代表是否需要提前来验证,解析我们的接口
        if (validateEagerly) {
    //serviceMethodCache中如果有缓存直接读取缓存,没有缓存则对接口中的所有方法解析成各种ServiceMethod,并存入
    serviceMethodCache中;详见下面的代码
          eagerlyValidateMethods(service);
        }
    
    //通过动态代理来创建我们网络请求的实例,newProxyInstance会传进来一个class对象,会生成一个实例(代理类),每当
    我们执行我们代理类的方法的时候就会调用new InvocationHandler()中的invoke方法,用于解析我们接口方法注解等操作
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, Object[] args)
                  throws Throwable {
               ...
    //最核心的三行代码,下一小节着重讲这三行代码
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                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 = serviceMethodCache.get(method);
        if (result != null) return result;
    //设置线程同步锁
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
    //创建新的ServiceMethod对象,并放入缓存池中
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    
    

    Retrofit中serviceMethod对象解析

    动态代理中invoke中最核心三行代码
    //loadServiceMethod看上文代码
    ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.callAdapter.adapt(okHttpCall);
    
    

    ServiceMethod类源码分析

    //包含我们访问网络的所有基本信息
    final class ServiceMethod<R, T> {
    //用于生产我们的网络请求call,默认是okhttpCall(实现Call<T>接口),对okhttp中的Call封装
      final okhttp3.Call.Factory callFactory;
    //网络请求适配器,适应不同平台
      final CallAdapter<R, T> callAdapter;
    
      private final HttpUrl baseUrl;
      private final Converter<ResponseBody, R> responseConverter;
    //网络请求的方法,get,post,put等
      private final String httpMethod;
      private final String relativeUrl;
    //网络http的请求头
      private final Headers headers;
    //网络请求的http报文的body类型
      private final MediaType contentType;
      private final boolean hasBody;
      private final boolean isFormEncoded;
      private final boolean isMultipart;
    //非常重要,方法参数的处理器,我们在定义接口的时候,参数跟注解都需要通过这个处理器处理
      private final ParameterHandler<?>[] parameterHandlers;
    
    static final class Builder<T, R> {
        final Retrofit retrofit;
    //网络请求的方法(接口中的方法)
        final Method method;
    //网络请求方法上的注解
        final Annotation[] methodAnnotations;
    //网络请求方法中参数的注解的内容
        final Annotation[][] parameterAnnotationsArray;
    //网络接口请求方法中参数的类型
        final Type[] parameterTypes;
    Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
          this.methodAnnotations = method.getAnnotations();
          this.parameterTypes = method.getGenericParameterTypes();
          this.parameterAnnotationsArray = method.getParameterAnnotations();
        }
    }
    
    /**
    *   总结:build()方法根据我们的返回值类型和方法中的注解来从我们的网络请求适配器工厂集合和我们的数据转换器工厂
    集合中分别获取到我们所需要的网络请求适配器和response数据转换器,然后根据我们参数,注解来获取我们需要解析的
    参数,最后调用parseParameter方法来解析我们接口中的参数
    **/
    public ServiceMethod build() {
    //createCallAdapter()代码主要是通过循环retrofit中的adapterFactories中CallAdapter.Factory.get方法获取不同平台的CallAdapter
          callAdapter = createCallAdapter();
          responseType = callAdapter.responseType();
    //创建数据转换器,通过循环retrofit中的converterFactories中Converter.Factory.responseBodyConverter方法获取不同平台的Converter
          responseConverter = createResponseConverter();
    
          for (Annotation annotation : methodAnnotations) {
    //解析方法上的注解
            parseMethodAnnotation(annotation);
          }
    
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0; p < parameterCount; p++) {
            Type parameterType = parameterTypes[p];
          Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    //对方法中参数及注解的解析,有Path,Query等类都是继承ParseParameter
           parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
          }
          return new ServiceMethod<>(this);
        }
    
    /**
    *  创建网络请求适配器
    **/
         private CallAdapter<T, R> createCallAdapter() {
    //获取方法返回值,例如Obserable<>
          Type returnType = method.getGenericReturnType();
    //获取方法注解
          Annotation[] annotations = method.getAnnotations();
    //通过retrofit中的adapterFactories中CallAdapter.Factory.get方法获取不同平台的CallAdapter
          return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
          }
    
    /**
    *  创建网络请求数据转换器
    **/
    private Converter<ResponseBody, T> createResponseConverter() {
         Annotation[] annotations = method.getAnnotations();
         return retrofit.responseBodyConverter(responseType, annotations);
         }
    
    }
    
    Retrofit中okHttpCall对象和adapt返回对象解析

    继续看之前的三行重要代码,上文解析了ServiceMethod类,接下来看OkHttpCall
    retrofit同步请求流程:对我们每个网络请求参数利用ParameterHandler来解析;根据创建好的ServiceMethod对象来创建http请求中需要的request对象;okhttp发送网络请求;Converter进行网络响应转换成java对象。retrofit主要通过接口跟注解来对http请求做了包装封装,让我们在使用只要把焦点放在接口的创建上,通过接口来配置方法跟参数,通过动态代理将接口方法转换成ServiceMethod对象,通过serviceMethod来获取我们想要的信息

    动态代理中invoke中最核心三行代码
    //loadServiceMethod看上文代码
    ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    //最终调用CallAdapter中的adapt方法转换,具体看下RxJava2CallAdapter
    return serviceMethod.callAdapter.adapt(okHttpCall);
    

    OkHttpCall源码

    对okhtt.Call的封装
    final class OkHttpCall<T> implements Call<T> {
      private final ServiceMethod<T, ?> serviceMethod;
    //请求参数
      private final Object[] args;
    //状态标志位,是否要去取消请求
      private volatile boolean canceled;
    
      // 实际的网络请求类
      private okhttp3.Call rawCall;
    //异常抛出
      private Throwable creationFailure; // Either a RuntimeException or IOException.
      //用在异步方法中判断逻辑
      private boolean executed;
    
      OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
      }
    
    //返回okhttp中的Request
    @Override public synchronized Request request() {
        Request request = serviceMethod.toRequest(args);
        rawCall = createRawCall();
    return rawCall.request();
    }
    
    @Override public void enqueue(final Callback<T> callback) {
    ......
    }
    
    @Override public Response<T> execute() throws IOException {
        okhttp3.Call call;
        call = rawCall = createRawCall();
         return parseResponse(call.execute());
      }
    
    //创建真正的网络请求Call,对网络请求接口中的每个参数调用parameterHandler来解析,然后通
    //过serviceMethod对象生成request,并生成okhttp中的Call
    private okhttp3.Call createRawCall() throws IOException {
    //serviceMethod中通过parameterHandlers去解析参数生成Request
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
       return call;
      }
    
    //解析请求回来后的数据
     Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    //调用serviceMethod中的转换器responseConverter.convert(body);
        T body = serviceMethod.toResponse(catchingBody);
          return Response.success(body, rawResponse);
    }
    
    }
    

    Retrofit涉及的别的知识点总结

    Retrofit接口注解

    retrofit注解类型.png
    第一类:网络请求方法
    retrofit网络请求方法.png

    @HTTP(method = "GET", path = "blog/{id}", hasBody = false)

    第二类:标记
    retrofit标记注解.png

    a. @FormUrlEncoded
    作用:表示发送form-encoded的数据
    每个键值对需要用@Filed来注解键名,随后的对象需要提供值。

    /**
     *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
     * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
    */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
    

    b. @Multipart
    作用:表示发送form-encoded的数据(适用于 有文件 上传的场景)
    每个键值对需要用@Part来注解键名,随后的对象需要提供值。

    /**
    * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
    * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息)
    */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
    
    
    //具体使用
    GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
     // @FormUrlEncoded 
    Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
    
    //  @Multipart
    RequestBody name = RequestBody.create(textType, "Carson");
    RequestBody age = RequestBody.create(textType, "24");
    
    MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
    Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
    

    第三类:网络请求参数


    retrofit网络请求参数注解.png

    详细说明
    a. @Header & @Headers

    作用:添加请求头 &添加不固定的请求头
    具体使用如下:

    // @Header
    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)
    
    // @Headers
    @Headers("Authorization: authorization")
    @GET("user")
    Call<User> getUser()
    
    // 以上的效果是一致的。
    // 区别在于使用场景和使用方式
    // 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
    // 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
    

    b. @Body
    作用:以 Post方式 传递 自定义数据类型 给服务器
    特别注意:如果提交的是一个Map,那么作用相当于 @Field
    不过Map要经过 FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:

    FormBody.Builder builder = new FormBody.Builder();
    builder.add("key","value");

    c. @Field & @FieldMap
    作用:发送 Post请求 时提交请求的表单字段
    具体使用:与 @FormUrlEncoded 注解配合使用

    public interface GetRequest_Interface {
            /**
             *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
             * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
             */
            @POST("/form")
            @FormUrlEncoded
            Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
    
    /**
             * Map的key作为表单的键
             */
            @POST("/form")
            @FormUrlEncoded
            Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
    
    }
    
    // 具体使用
             // @Field
            Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
    
            // @FieldMap
            // 实现的效果与上面相同,但要传入Map
            Map<String, Object> map = new HashMap<>();
            map.put("username", "Carson");
            map.put("age", 24);
            Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
    

    d. @Part & @PartMap
    作用:发送 Post请求 时提交请求的表单字段
    与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景

    e. @Query和@QueryMap

    • 作用:用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)

      如:url = http://www.println.net/?cate=android,其中,Query = cate

    • 具体使用:配置时只需要在接口方法中增加一个参数即可:

      @GET("/")    
       Call<String> cate(@Query("cate") String cate);
    }
    
    // 其使用方式同 @Field与@FieldMap,这里不作过多描述
    
    

    Retrofit设计模式

    构建者模式:将一个复杂对象的构建跟表示相分离,主要是对象创建的复杂程度对我们用户来说是不需要知道的,只需要调用builder内部类通过它的链式调用来初始化。

    工厂模式:在retrofit中CallAdapter.Factory有get方法,获取不同的CallAdapter;不同的网络适配器工厂只要集成这个Factory并实现get方法就能生产自己平台的CallAdapter。Platform中的findPlatform也是个静态的工厂方法。

    外观模式:门户模式,外部与一个子系统的通信必须通过一个统一的外观对像来进行。Retrofit对外统一的对外类就是Retrofit

    策略模式:不使用策略时,一般用if ;else if判断不同的方法策略;以后如果需要添加新的方法策略时需要改以前的代码,维护成本高。一般有几个角色:1.Context(上下文);2.抽象的策略类Strategy;3.具体的策略实现类ConcreteStrategyA。context会使用Strategy接口来调用具体的ConcreteStrategy来实现方法。例如CallAdapter类(Strategy);Retrofit(Context);RxjavaCallAdapter(ConcreteStrategy)。工厂模式侧重于生成不同的对象;策略模式侧重于不同对象方法的实现。

    适配器模式:将接口转换成客户端希望的接口,使本不兼容的类能一起工作。例如CallAdapter类中的adapt方法,将我们的okhttpcall适配成适应不同平台的网络请求call;okhttpcall只有执行网络请求功能,但retrofit是支持很多平台的,请求有各自的特性,通过适配器将okhttpcall适配成适配不同平台的Call

    观察者模式:建立一个对象跟多个对象之间的依赖关系,当一个对象变化时会自动通知观察它的对象进行改变。

    Hook

    通过某种手段对一件事物进行改头换面,从而劫持Hook的目标来以达到控制目标的行为的目的;两种方式实现:反射跟动态代理

    MVP,MVC

    mvc:Model View Controller,将我们的业务逻辑,数据显示,界面相分离。
    mvp跟mvc最大区别就是mvc是允许Model跟View交互的,而MVP则不允许View跟Model交互;
    mvp缺点:P层臃肿,V跟P的耦合,接口颗粒度(接口过多过少都有影响)

    SharedPreferences

    跨进程读取:设置模式为Context.MODE_MULTI_PROCESS(该属性为deprecated),但有数据安全问题,官方推荐Contentprovider。

    SharedPreferences文件的一种,底层采用xml文件,安卓系统对xml文件的读取有缓存策略,在内存中会有xml的一份缓存,导致多进程环境下每个进程都会保存一份SharedPreferences文件,这样就会读写的时候造成读写不一致。

    apply()和commit()区别:apply是一个没有返回值的方法,将我们修改的数据提交到内存(commitToMemory),并异步把数据提交到硬盘(enqueueDiskWrite(runable))。commit方式有返回值boolean,是同步将我们数据放到硬盘中

    相关文章

      网友评论

          本文标题:Retrofit源码笔记

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