Retrofit2 初探

一、前言

之前看了okhttp的源码,然后我们的项目中一般都是okhttp + retrofit组合的形式,所以也想看一下retrofit的源码,看看它是如何通过注解与okhttp组合进行网络请求的。本文只是记录一下自己的学习过程,理解一下retrofit的执行流程,将整个网络请求过程打通。


二、源码流程讲解

说明:代码讲解主要围绕使用的流程来讲解

2.1、retrofit的调用方式
 Retrofit rxRetrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create()) //添加一个转换器,将gson数据转换为bean类
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  //配合Rxjava使用的时候添加的回调适配器
                .client(okHttpClient) //添加okhttpClient
                .build();
        ixxxServer = rxRetrofit.create(IXXXServer.class);
2.1.1 Retrofit.Builder()

说明:该方法主要是进行Retrofit使用平台的初始化,retrofit支持Android和Java8两个平台,代码如下:

public Builder() {
      this(Platform.get());
    }
//Platform.java
 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();   //Android平台
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8(); //java8平台
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
2.1.2 baseUrl(baseUrl)

说明:传入baseUrl,如:http://www.baidu.com/, 该方法主要是传值,并校验该值是否为空

2.1.3 addConverterFactory(XXX) addCallAdapterFactory(XXX) build()

说明:这两个方法在retrofit的逻辑基本上是一致的,都是分别有一个list存储转换器和适配器,并都有一个默认的值,代码如下:

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {  //如果callFactory为空时,创建一个OkHttpClient
        callFactory = new OkHttpClient();
      }
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) { 
        callbackExecutor = platform.defaultCallbackExecutor(); //创建一个默认的callbackExecutor 
      }

      // callAdapterFactories 为存储适配器的集合
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      //platform.defaultCallAdapterFactories(callbackExecutor) 为默认的适配器
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
        
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
     return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

最终,这两个集合传入Retrofit的构造函数中,作为参数一遍后面的逻辑使用。那么问题来了,这个集合存储了好几个适配器,那他们是如何定位到我们所需要的那个适配器呢?答案是,根据我们 请求网络的方法的返回值进行匹配,后面会讲到。

2.1.4 client(okHttpClient)

说明:传入okhttpClient值,retrofit内部将该值存储为callFactory,该值,作为retrofit链接okhttp的桥梁。


2.2 ixxxServer = rxRetrofit.create(IXXXServer.class)

说明:该方法为Retrofit的核心入口,前面那些调用,仅是一些基本的赋值操作,而该方法则是处理retrofit用到的注解、返回值等必要因素,并利用代理的方式生成IXXXServer的代理,然后我们就可以用生成的代理直接调用方法。代码如下:

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //这个地方是核心
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

说明:上面newProxyInstance()这个方法有三个参数,第一个是类加载器,第二个是一个Interface对象的数组,即我们需要代理的Interface,这里我们是IXXXServer,第三个为一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,我们主要看的是InvocationHandler的invoke()这个方法,该方法也有三个参数:

  • proxy 动态代理,指代我们所要代理的那个真实的对象,如 IXXXService.java这个类
  • method 真实代理类中的方法,如:IXXXService类中的 getData(33,89)
  • args 方法中接收的参数,如上面的getData的(33,89)

在inivoke()方法中,重点在于 loadServiceMethod(method).invoke(args != null ? args : emptyArgs);,这行代码,我们拆分为两部分,首先是,然后是invoke(args != null ? args : emptyArgs)

2.2.1 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) {
        result = ServiceMethod.parseAnnotations(this, method); //这行是重点
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

说明:上面有一个serviceMethodCache字段,为一个Map集合Map<Method, ServiceMethod<?>>,方法为key,ServiceMethod为value,其中ServiceMethod是处理IXXXService方法中的注解、返回值对象,类型等的类的一个入口类(真正处理的是在RequestFactory),我们重点看下 result = ServiceMethod.parseAnnotations(this, method)这一行代码,实现是在SerViceMethod.java中:

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //重点,解析方法的注解
    Type returnType = method.getGenericReturnType(); //获得方法返回类型
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); //重点
  }

说明:这个方法中有两行代码比较重要,我们首先看下 RequestFactory.parseAnnotations(retrofit, method)这个方法,点进去到RequestFactory这个类中,看到该方法实际执行了一个new Builder(retrofit, method).build()方法,首先看下前面那部分,new Builder(retrofit, method)。代码如下:
前置:

@GET("/api/user-purchased/v1")
fun getHavePurchasedList(@Query("page") page: Int?,
                   @Query("limit") limit: Int?): Observable<V2ResponseModel<List<HavePurchasedRawDataModel>>>
Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit; //前面传进来的retrofit
      this.method = method; //我们所要调用的方法
      this.methodAnnotations = method.getAnnotations(); //获得方法的注解 如:@GET
      this.parameterTypes = method.getGenericParameterTypes(); //获得方法中参数的类型 如:Int
      this.parameterAnnotationsArray = method.getParameterAnnotations(); //获得方法中参数的注解 如:@Query
    }

然后我们再看下build()这个方法:

{
      for (Annotation annotation : methodAnnotations) { //遍历上面得到的方法注解
        parseMethodAnnotation(annotation); //解析每个注解
      }
      
     ......代码省略......
     
      int parameterCount = parameterAnnotationsArray.length; //获得参数注解的个数
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]); //解析参数注解
      }
    ......代码省略......
      return new RequestFactory(this);
    }

说明:我们先看下parseMethodAnnotation(annotation)这个方法,如下:

private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

其中每个注解都会调用parseHttpMethodAndPath这方法,最后是得到@GET("/api/user-purchased/v1")里面的值/api/user-purchased/v1,用relativeUrlParamNames这个字段进行保存,我们重点看一下下面的几行代码:

 int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
      }

说明:该方法最终执行 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]),这个方法有三个参数,第一个为p,是参数注解的index,第二个是该index的参数类型,第三个是该index上参数的注解,我们继续点进去看一下:最终执行的是:

private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
        
    ...... 代码省略......
     if (annotation instanceof Path) { //解析Path
      ...... 代码省略.....
      } else if (annotation instanceof Query) {
       validateResolvableType(p, type);
        Query query = (Query) annotation; //参数注解
        String name = query.value(); //参数的值
        boolean encoded = query.encoded();  //是否编码

        Class<?> rawParameterType = Utils.getRawType(type); //返回承载该泛型信息的对象,如:List<String>中的List
        gotQuery = true;
        if (Iterable.class.isAssignableFrom(rawParameterType)) {  //判断是否是集合
          if (!(type instanceof ParameterizedType)) {
            throw parameterError(method, p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + "<String>)");
          }
          ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); //用于获取泛型的参数 如:List<String> 中的String
           //这个coverter将参数转成字符串,利用到了我们一开始传入的BuiltInConverters,后面有代码讲解
          Converter<?, String> converter =
              retrofit.stringConverter(iterableType, annotations);
              //返回一个操作参数的句柄,在我们okhttpClient将会使用到,此处仅仅是数据存储
          return new ParameterHandler.Query<>(name, converter, encoded).iterable(); 
        } else if (rawParameterType.isArray()) { //判断是否是数组
          Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter<?, String> converter =
              retrofit.stringConverter(arrayComponentType, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded).array();
        } else { //参数非数组或者集合
          Converter<?, String> converter =
              retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded);
        }


      } else if (annotation instanceof QueryName) {
      ...... 代码省略......

      } else if (annotation instanceof QueryMap) {
     ...... 代码省略......
        return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());

我们再看下上面说到的Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations)这一行将参数转成字符串的代码

 public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");
......代码省略......
    return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE; //初始化一个ToStringConverter
  }

至此,我们的ServiceMethod的解析参数的RequestFactory.parseAnnotations(retrofit, method)流程已经说完,返回RequestFactory对象,我们再看ServiceMethod类中的parseAnnotations方法的最后一行代码

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//解析的注解返回RequestFactory的对象
......代码省略......
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); //在HttpServiceMethod类中解析注解
  }

由此,我们进入HttpServiceMethod类中的parseAnnotations方法,代码如下:

//三个参数:retrofit,指代我们所创建的这个retrofit,method,我们所代理的方法,factory,上面返回得RequestFactory对象
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method); //获得一个CallAdapter,下面会讲
    //获得我们服务器响应的返回值类型,例如Observable<V2ResponseModel<MarketStatusListModel>> 中的V2ResponseModel<MarketStatusListModel>
    Type responseType = callAdapter.responseType(); 
  ......代码省略......
  //获得响应数据的转换器,例如GsonConverterFactory
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    okhttp3.Call.Factory callFactory = retrofit.callFactory; // HttpCallFactory,这个callFactory字段很重要,将retrofit盘活了
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }

下面我们看下上面说到的获取callAdapter的方法CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method),最后执行的方法如下:

参数说明:第一个参数,此参数始终为空null,第二个参数 方法的泛型返回值类型,第三个参数,方法的注解
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    ......代码省略......
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
......代码省略......
  }

说明:该方法遍历我们callAdapterFactories所存储的callAdapter,我一开始讲解这个集合的时候有一个疑问,就是我们如何得到我们想要的那个或者说我们传入的那个callAdapter呢,答案就是在这里,get(returnType, annotations, this)这一行,根据我们的返回值类型及注解,来判断我们所要的那个callAdapter。至于如何得到该adapter,大家可以看RxJava2CallAdapterFactory这个类,我这里就不说了。
我们在我那个上一层看: return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter)
此处返回一个HttpServiceMethod类,里面的参数我们拿到了我们解析方法参数的requestFactory,Okhttp 的callFactory,callAdapter以及数据转换的responseConverter,由此,retrofit数据请求的所有的前期准备已经完备了,类似于我们做一个电器,并让它能够运转,电器准备好了,接上电源就好了,我们电源也准备好了OKHTTP3,现在,我们只要一个接头,接入即可,那么这个接头是啥呢?我们一开始分析的Retrofit类中的create()方法中那个代理方法中的loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法的前半部分loadServiceMethod,我们还有invoke方法没有说明,那么这个invoke方法,就是我们刚才比喻的接头,下面我们上代码:

@Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

说明:该方法是ServiceMethod这个类的抽象方法,其实现在HttpServiceMethod类中,我们看上面的代码只有一行,有几个关键的点,第一、callAdapter.adapt(),第二、OkHttpCall,我们分开讲。

callAdapter.adapt()

有人会问,这个callAdapter是什么,这个callAdapter是我们上面分析到的得到的那个callAdapter

return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);

看见第三个参数没,就是这个,例如加入我们传入的是RxJava2CallAdapterFactory,在该类中的get方法中有一行代码是创建RxJava2CallAdapter的代码,如:

 public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
......代码省略......
    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }

然后我们在看下adapt方法,由于我用的是RxJava2CallAdapterFactory,我就用RxJava2CallAdapter来讲解吧,代码如下:

//这个call为我们上面说到的OkHttpCall
@Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync  //isAsync 是否异步
        ? new CallEnqueueObservable<>(call) //异步
        : new CallExecuteObservable<>(call); //同步

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }
......代码省略......
    return observable;
  }

我这边就将异步执行吧,我们按照代码跳到CallEnqueueObservable这个类中,new CallEnqueueObservable<>(call) 这个方法只是进行赋值,真正关键在于subscribeActual这方法

@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone(); //originalCall为刚才传入的值
    CallCallback<T> callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
    call.enqueue(callback); //这行是开始执行,这是重点
  }

我们再看下OKHttpCall这个类中的enqueue方法

 @Override public void enqueue(final Callback<T> callback) {
 ......代码省略......
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall(); //这行是重点,下面会讲
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure); //失败回调
      return;
    }

    if (canceled) {
      call.cancel();
    }
   .....代码省略......
  }

说明,我们这边看下call = rawCall = createRawCall()这个方法

private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

说明:callFactory.newCall()方法执行的是okhttp3里面的方法,我们重点看下该方法传入的参数requestFactory.create(args),create()方法里面的args为我们请求网络时的参数,我们再看下requestFactory.create()这个方法

okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    //parameterHandlers字段为之前所说的解析方法注解之后返回的一个操作句柄
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    int argumentCount = args.length;
    ......代码省略......
    //创建requestBuilder ,传入的参数包括请求方式,完整的请求Url等
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }

最后,我们就将retrofit与okhttp已经连接起来了。最后有一个问题就是返回的数据,是在哪里进行转成我们所需要要的model呢,我们回到OkHttpCall的enqueue方法,看到有一行是拿到上面返回的call,然后再执行enqueue方法

@Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
......代码省略......
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);//这里是解析响应数据,并返回我们所想要的那种数据类型
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response); //成功回调
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e); //失败回调
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

成功回调之后CallEnqueueObservable中的onResponse()方法得以执行,代码如下:

@Override public void onResponse(Call<T> call, Response<T> response) {
      if (call.isCanceled()) return;
      try {
        observer.onNext(response);
        if (!call.isCanceled()) {
          terminated = true;
          observer.onComplete();
        }
      } catch (Throwable t) {
        if (terminated) {
          RxJavaPlugins.onError(t);
        } else if (!call.isCanceled()) {
          try {
            observer.onError(t);
          } catch (Throwable inner) {
            Exceptions.throwIfFatal(inner);
            RxJavaPlugins.onError(new CompositeException(t, inner));
          }
        }
      }
    }

上面我们看到了Rxjava的熟悉的方法onNext()onComplete()方法,至此,我们在代码中便可收到响应的数据,一个完整的流程走完了。


三、总结

通过查看代码可知道,其实retrofit只是对okhttp的上层数据进行一次封装,让用户使用起来更加的方便,而真正的网络请求则是在OKHttp中,retrofit重要的两个点在于代理以及解析方法的注解。哈哈,说的好简单

四、写在最后

本人水平有限,看源码比较粗浅,只能对源码的大概流程了解,有一些地方还是有些不太明白,哈哈,有些地方就带过啦。写这个博文写了好多天,其实看明白与写出来还是有比较大的差距的,我也不想胡乱写,有些地方还是得查资料,所示花的时间比较长。有分析的不对的地方,欢迎大佬指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值