Retrofit的实现与原理

Retrofit的使用

1、首先是创建一个interface的请求集合,里面用注解的方式写入需要配置的请求方法

public interface Service {
@GET("/repos/{user}/repos")
Call<List<Repo>> contributors(
    @Path("user") String user);
}

2、然后通过Retrofit定义一个上面接口的实现类,就是所谓的动态代理

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

// Create an instance of our Service API interface.
Service service = retrofit.create(Service.class);

3、之后就是接口请求

Call<List<Repo>> call = service.repos("GitHub");

源码解析

Retrofit2源码如下,主要是通过Retrofit.create(Class)方法创建出Service interface 实例,从而使得Service中配置的方法变得可用,这就是retrofit的核心;

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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();

          @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);
            }
            //这里的三行代码是关键
            ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
    });
}

方法内部具体实现:
使用Proxy.newProxyInstance()来创建service实例。这个方法会为参数中多个interface(具体到Retrofit,是固定传入一个interface)创建一个对象,这个对象实现所有interface的每个方法,并且每个方法都调用对象实例内部的一个InvocationHandler成员变量的invoke()方法,并把自己的方法信息传递出去。这样就在实质上实现了代理逻辑:interface中的方法全部由另外一个设定的InvocationHandler对象来进行代理操作,即动态代理。这些方法的具体实现是在运行时生成interface实例才确定的。
因此,invoke()方法中的逻辑,就是Retrofit创建service的关键,完成三步:

1、加载对应method的ServiceMethod实例(包括返回值类型、方法注解、参数类型、参数注解)
2、使用ServiceMethod所包含的信息创建OkHttpCall对象。将ServiceMethod封装进一个retrofit2.call对象,在其需要的时候被调用,利用ServiceMethod中包含的信息来创建一个okhttp3.call对象,并调用这个okhttp3.call对象来发起网络请求。
3、使用ServiceMethod中的callAdapter对象来把okHttpCall对象进行转换,生成一个新的retrofit2.call对象,在这个新的call对象中,后台线程发起请求,会在相应返回后,从主线程中调用回调方法,实现线程的切换。

第一步,加载method对应的ServiceMethod

通过loadServiceMethod()方法获取

ServiceMethod<?, ?> loadServiceMethod(Method method) {
//检查serviceMethodCache是否存在method对应的实例缓存,存在就是用,不存在就new
  ServiceMethod<?, ?> result = serviceMethodCache.get(method);
  if (result != null) return result;

  synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
   }
   return result;
}

如果serviceMethodCache不存在缓存,就调用ServiceMethod.Build.build()方法新建

public ServiceMethod build() {
  //生成callAdapter
  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,结果转换的
  responseConverter = createResponseConverter();
  //遍历,分析注解,你的请求是GET、POST等,然后拼凑url
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
  //以下都是验证参数、注解是否合法
  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }

  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);
  }

  if (relativeUrl == null && !gotUrl) {
    throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
  }
  if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError("Non-body HTTP method cannot contain @Body.");
  }
  if (isFormEncoded && !gotField) {
    throw methodError("Form-encoded method must contain at least one @Field.");
  }
  if (isMultipart && !gotPart) {
    throw methodError("Multipart method must contain at least one @Part.");
  }
  //最后返回ServiceMethod
  return new ServiceMethod<>(this);
}

第二步,method、注解的参数args创建OkHttpCall

OkHttpCall实际上就是OkHttp3.call的一个包装类,而且创建OkHttpCall内部实际上最终调用的是serviceMethod.callFactory.newCall(request)方法创建的OkHttp3.call来执行网络请求。

第三步,调用serviceMethod.callAdapter.adapt(okHttpCall)来产生method所定义的返回

这个⽅方法会使⽤用 ServiceMethod 中的 callAdapter 对象来把 okHttpCall 对象进⾏行行转换,⽣生成⼀个新的 retrofit2.Call 对象,在这个新的 Call 对象中,后台线程发起的请求,会在相应返回后,从主线程中调⽤用回调⽅方法,实现线程的⾃自动切换。其中在Android平台Retrofit2.build() 的时候会自动使用主线程handler构造一个ExecutorCallAdapterFactory,调用enqueue(Callback),callback回调会在主线程中回调

static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
      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);
    }
  }
}

扩展:
正因为T adapt(Call< R > call)可以实现类型转换,并且在Retrofit的扩展Adapter中还提供了RxJavaCallAdapterFactory,Java8CallAdapterFactory,GuavaCallAdapterFactory

以RxJavaCallAdapterFactory为例,RxJavaCallAdapterFactory创建的callAdapter在执行adapt时将OkHttpCall包装一个Rx的Observable,在Observable被subscribe时才会真正的执行http请求。

参考:Retrofit原理浅析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值