Retrofit详解

已经有了okhttp,为什么还需要Retrofit:

  1. 自动转换数据格式
    • 您提到Retrofit提供了自动转换数据格式的功能,这是非常准确的。Retrofit可以与多种转换器(如Gson、Jackson、Moshi等)集成,自动将HTTP响应体转换为Java对象,同样也可以将Java对象转换为请求体。这大大简化了数据处理的代码,使得开发者无需手动解析JSON或构建请求体。
  2. 声明式的API
    • Retrofit确实提供了声明式的API,这是它的一大亮点。通过简单的接口定义,开发者可以轻松地描述HTTP请求(如GET、POST等)的URL、请求方法、请求头和请求体等。这种方式使得HTTP请求的配置更加直观和易于管理。
  3. 配合RxJava
    • 您提到Retrofit可以配合RxJava使用,这也是非常正确的。Retrofit 2.x版本开始支持RxJava 2.x,允许开发者以响应式编程的方式处理HTTP请求。通过RxJava,开发者可以更加灵活地处理异步操作、错误处理、数据转换等,使得代码更加简洁和可读。

1:用法:

Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl("https://api.github.com/")
                .build();

        GithubService service = retrofit.create(GithubService.class);
        service.listRepos("woniupanpa").enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                Log.d("yjm" ,"success" + gson.toJson(response.body()));
                System.out.println("yjm success");
            }

            @Override
            public void onFailure(Call<List<Repo>> call, Throwable t) {

            }
        });

 

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

    @GET("users/{user}/repos")
    Call<List<Repo>> getUser(@Path("user") String user);
}

 


2:源码:

1)create():

 

public <T> T create(final Class<T> service) {
    validateServiceInterface(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 @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

 

解析:该方法采用动态代理的模式,所谓动态代理是这样的,举个例子:

代理类A和被代理类B,他们都继承自接口 C,并且A持有B的实例,这样,B里面的任何方法都要经过A的invoke执行,这样,A就能够实现对B的所有方法的统一监控,在Retrofit里面就类似这样:

接口:

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

    @GET("users/{user}/repos")
    Call<List<Repo>> getUser(@Path("user") String user);
}

被代理类:BService

public class BService implements GithubService{

        @Override
        public Call<List<Repo>> listRepos(String user) {
            return null;
        }

        @Override
        public Call<List<Repo>> getUser(String user) {
            return null;
        }
    }

代理类A:

public class RealService implements GithubService{

    InvocationHandler invocationHandler = new InvocationHandler() {
        @Override
        public @Nullable 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);
            }
            args = args != null ? args : emptyArgs;
            return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
        }
    });

    @Override
    public Call<List<Repo>> listRepos(String user) {
        try {
            Method method = GithubService.class.getMethod("listRepos");
            return (Call<List<Repo>>) invocationHandler.invoke(this, method, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }finally {
            return null;
        }
    }

    @Override
    public Call<List<Repo>> getUser(String user) {
        try {
            Method method = GithubService.class.getMethod("getUser");
            return (Call<List<Repo>>) invocationHandler.invoke(this, method, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }finally {
            return null;
        }
    }

}

以上代码就实现了:被代理类ServiceB的所有方法都交给代理类RealService执行,即都会经过RealService的invoke()方法。

这样,代理类RealService就能更实现对被代理类BService 的所有方法的统一监控。

在Retrofit案例中,比较特殊的一点是,它不存在被代理类BService这个角色,它有的只是接口GithubService和代理类RealServce,

GithubService:

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

    @GET("users/{user}/repos")
    Call<List<Repo>> getUser(@Path("user") String user);
}

RealServce:RealService的实例就是:Proxy.newProxyInstance....

通过以上分析就能够得出以下结论:

GithubService service = retrofit.create(GithubService.class);

该代码得到的是一个GithubService这个接口对应的动态代理模式中的代理类RealService的实例

当应用层代码执行:service.listRepos("woniupanpa")的时候,就是把listRepos这个方法丢进RealService的invoke执行:

@Override
              public @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }

所以这里面的methode,对应的是GithubService这个接口里面的方法,当应用层调用任意一个接口的时候,都会经过该方法。

我们在乎的是method方法里面定义的注解和参数,比如@Post, @Body,这些才是我们需要的东西,所以我们看到,在应用层,我们只需要去定义接口就可以,不必关心该类真正的实现,所以也不需要存在被代理类。

 

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

    @GET("users/{user}/repos")
    Call<List<Repo>> getUser(@Path("user") String user);
}

 

2)ServiceMethod

@Override
              public @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }

看最后一行loadServiceMethod(method).invoke(args)->

 

ServiceMethod.parseAnnotations(this, method);->

 

RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);->

 

return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

 

parseAnnotations:

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:

Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

methodAnnotations是接口的注解,@GET("users/{user}/repos")

parameterTypes是参数:String user

parameterAnnotationsArray :是参数的注解@Path("user")

由此可知:loadServiceMethod(method).invoke(args)执行的是HttpServiceMethod的invoke:

@Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

 

3)HttpServiceMethod:

@Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

CallAdapted继承HttpServiceMethod,所以执行CallAdapted的adapt:

 @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }

往回翻会发现,callAdapter来自HttpServiceMethod的parseAnnotations:

CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

到此为止,先总结一下:

loadServiceMethod(method).invoke(args)执行的是:

CallAdapted的invoke,因为CallAdapted继承自HttpServiceMethod,即HttpServiceMethod的invoke()方法。

继续往下:

createCallAdapter:

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }

到Retrofit的nextCallAdapter:

public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");

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

由此可知,CallAdapter的实例来自callAdapterFactories,再看看callAdapterFactories来自哪里:

Retrofit(
      okhttp3.Call.Factory callFactory,
      HttpUrl baseUrl,
      List<Converter.Factory> converterFactories,
      List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor,
      boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

往上找最终会发现,来自应用层代码:

 Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl("https://api.github.com/")
                .build();

如果用户层没有添加addCallAdapterFactory,那么他还有有一个默认的defaultCallAdapterFactories:

 List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

假设我们这时候没有添加,那么总结一下:loadServiceMethod(method).invoke(args)执行的是HttpServiceMethod的invoke:

DefultCallAdapterFactory里面的CallAdapter的adapt():

@Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }

这里的call来自HttpServiceMethod的,即是一个OkhttpCall

 @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

再回到DefultCallAdapterFactory里面的CallAdapter的adapt():可知

最终执行的到OkhttpCall的enqueue,发起异步通讯。

 

posted @ 2023-02-24 08:30  蜗牛攀爬  阅读(103)  评论(0编辑  收藏  举报