Retrofit使用与分析

2019-08-01  本文已影响0人  莫库施勒

用法示例

定义接口
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
实例化接口
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

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

Call<List<Repo>> repos = service.listRepos("octocat");
API定义
// 普通定义
@GET("users/list")

// 添加变量
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
// 如 map
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
// 如 body
@POST("users/new")
Call<User> createUser(@Body User user);

// POST and PUT
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

// Headers
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
// 或者
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
添加格式转换
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);
Gson注解
public class Box {

  @SerializedName("w")
  private int width;

  @SerializedName("h")
  private int height;

  @SerializedName("d")
  private int depth;

  // Methods removed for brevity
}

原理

在上面的例子中我们看到了,我们会将定义好的接口实例化出来,通过create()方法,现在我们来看具体的实例过程:

  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.adapt(okHttpCall);
          }
        });
  }

从代码中我们看到我们通过Proxy.newProxyInstance()为这个接口创建了一个代理,当我们调用接口中的方法的时候就会进入invoke()方法,它的重点再最后三个语句

  1. 通过相应的method的参数和注解包装出一个 ServiceMethod
  2. 通过这个ServiceMethod创建出一个 OkHttpCall
  3. ServiceMethod中包括一个CallAdapter的成员变量,这个变量会对这个Call做一些处理,如:RxJava、Default等。来返回相应的Call

Retrofit.build()中,还需要一个CallAdapterFactory,它用来将 Call封装成一个CallbackCall,在它的enqueue()方法中调用了 OkHttpCall 的 enqueue,所以这里相当于静态的代理模式。OkHttpCall 中的 enqueue 其实又调用了原生的 OkHttp 中的 enqueue,这里才真正发出了网络请求,部分代码如下

@Override 
public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");
    //真正请求网络的 call
    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      //省略了部分发代码
      ...
      call = rawCall;
      //enqueue 异步执行
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
        //解析数据 会用到 conveterFactory,把 response 转换为对应 Java 类型
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }
   ...
}
上一篇下一篇

猜你喜欢

热点阅读