美文网首页
Retrofit 2调用流程解析

Retrofit 2调用流程解析

作者: BlackL | 来源:发表于2016-03-08 00:53 被阅读0次

    Retrofit使用

    若要请求api

    https://api.github.com/users/{user}/repos

    需要先创建一个接口

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

    然后创建一个Retrofit对象

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .build();
    
    GitHubService service = retrofit.create(GitHubService.class);
    

    可以看到通过retrofit.create()方法,retrofit为我们创建了一个GitHubService的实现,感觉很不可思议。
    紧接着就可以通过这个GitHubService的实现对象去请求网络了

    Call<List<Repo>> repos = service.listRepos("octocat");
    
    // Fetch and print a list of the contributors to the library.
    List<Contributor> contributors = call.execute().body();
    

    看到这里总是很疑惑,retrofit是如何用我们提供的接口来为我们创建出一个实例的呢?

    Retrofit调用流程

    从上面我们可以看到service实例是通过retrofit.create()方法获得的,那我们不看一下这个create()方法

    @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, 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 loadMethodHandler(method).invoke(args);
              }
            });
      }
    

    可以看到该方法返回的并不是一个service接口的实例,而是一个动态代理对象,而他又是怎么通过动态代理去发送网络请求的呢?我们就需要查看

    return loadMethodHandler(method).invoke(args);
    

    这行代码的返回结果了,去查看loadMethodHandler()方法

    private final Map<Method, MethodHandler> methodHandlerCache = new LinkedHashMap<>();
    
    MethodHandler loadMethodHandler(Method method) {
        MethodHandler handler;
        synchronized (methodHandlerCache) {
          handler = methodHandlerCache.get(method);
          if (handler == null) {
            handler = MethodHandler.create(this, method);
            methodHandlerCache.put(method, handler);
          }
        }
        return handler;
    }
    

    可以看到该方法先去试图从methodHandler的缓存map中去寻找相应的methodHandler,若不存在再去创建对应方法的MethodHandler,获得了相应的MethodHandler实例后再去调用去invoke()方法来发送请求。
    继续查看MethodHandler的invoke()方法

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

    其中callAdapter.adapt()方法负责把service中的返回类型转换成其他类型,例如RxJavaCallAdapter把返回结果转换成了Observable类型
    可以看到adapt方法中传入了一个OkHttpCall参数,而最后发送出网络请求的正是在该类的

    @Override public void enqueue(final Callback<T> callback)
    @Override public Response<T> execute() throws IOException
    

    这两个方法中。相关的Http请求信息则封装在了requestFactory这个对象中。

    这样整个流程就清楚了,可以看到这与我们一般使用动态代理的方法是不同的。这里对动态代理的使用是通过调用动态代理对象的相应方法,去生成一个Http请求再来发送这个请求。而service接口中方法的信息则是通过反射来得到的。

    </br>

    相关文章

      网友评论

          本文标题:Retrofit 2调用流程解析

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