Netandroid网络开发Android

Retrofit源码详解

2017-01-09  本文已影响717人  CoderMonkey

Retrofit的使用从很早之前就已经开始了, 但是一直没有深入研究为什么使用Retrofit只要定义一个接口, 同时在接口的方法上和方法的参数上加上一些注解就可以完成Http请求了, 也没有研究请求参数和请求结果是如何进行封装的, 所以使用Retrofit一直是处于一知半解的状态, 不知道其内部的原理, 因此花了一点时间看了Retrofit的源码, 对Retrofit的整个请求流程有了一定的理解.

Retrofit核心源码解读

1. 创建Retrofit对象

创建Retrofit对象的时候使用的是Builder模式, 可以在创建Retrofit对象的时候设置RetrofitbaseURL, 添加自己的converterFactory

例子:

Retrofit retrofit = new Retrofit.Builder()
           .baseUrl(GITHUB_API)
           .addConverterFactory(GsonConverterFactory.create())
           .build();

注意点:

2. 创建发送请求的接口

包含发送请求方法必须是一个接口, 同时这个接口是不能继承其他的接口的

例子:

    public interface GitApi {
        @GET("/users/{user}")
        Call<GitModel> getFeed(@Path("user") String user);
    }

注意点:

3. 发送Http请求

要发送http请求就离不开ServiceMethod类和OkHttpCall类, 他们是发送Http请求的核心类. 首先会从Map中获取和当前请求方法相关联的ServiceMethod, 如果找到了(说明之前这个方法已经被调用过了)就直接使用找到的ServiceMethod, 如果没有找到, 则创建一个新的ServiceMethod并且和当前的请求方法相关联putMap中. 最后调用OkHttpCall.execute发送请求.

源码:

  // 查找或者判断和请求的方法相关联的ServiceMethod
  
    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        // 缓存技术
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        // 使用了两次判断(两段锁)
        synchronized (serviceMethodCache) {
          // 这一次从缓存中取是有必要的且非常重要, 如果没有这一次则有可能下面的代码会被重复执行, 同一个key也可能被重复赋值
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
    }

源码:

public ServiceMethod build() {
 // 创建callAdapter对象(默认使用的是DefaultCallAdapterFactory), callAdapter对象用于.
 // callAdapter对象的主要作用就是返回一个CallAdapter接口的实例用于调用底层okhttp的方法发送请求和解析返回值(DefaultCallAdapterFactory中使用OkHttpCall.execute来发送请求和解析结果). 
 // 默认的请求方法返回值都是Call<T>, 可以继承CallAdapter.Factory来实现自定义的返回值类型
 callAdapter = createCallAdapter();
 
 ...
 other code
 ...
 
 // 创建返回值解析器(默认只有BuiltInConverters), 可以在创建Retrofit的时候使用addConverterFactory加入其他的converters
 responseConverter = createResponseConverter();

    // 解析方法上的注解
 for (Annotation annotation : methodAnnotations) {
   parseMethodAnnotation(annotation);
 }

 ...
 other code
 ...
 
 // 解析参数
 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);
 }

 ...
 一些错误情况的处理
 ...

 return new ServiceMethod<>(this);
}

关键代码:

    @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    
    synchronized (this) {
      
      ...
        
      call = rawCall;
      if (call == null) {
        try {
          // 创建Okhttp的call方法
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          ...
        }
      }
    }
        
     ....
    
     // call.execute: 调用okhttp发送真正的请求
     // parseResponse: 对返回的结果进行解析, 方法就是调用创建retrofit时加入的所有converterFactory, 知道找到一个converter可以处理返回值
    return parseResponse(call.execute());
  }

总结

至此, Retrofit发送请求的整个流程就已经讲解完毕了, 实际上整个流程中关键点就只有几个, 比如:

另外, Retrofit提供了

Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

这写转换器, 应该可以满足日常开发需要了.

从上面可以看到, Retrofit可以允许我们自定义返回类型, 返回结果同时屏蔽掉了底层的OkHttp的复杂性, 使得我们只要定义一个接口就完成Http请求的发送, 这对于使用者来说是非常友好的. 易于上手和高度的定制性是现如今Retrofit如此流行的关键

上一篇下一篇

猜你喜欢

热点阅读