美文网首页
Retrofit使用与分析

Retrofit使用与分析

作者: 莫库施勒 | 来源:发表于2019-08-01 17:21 被阅读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);
          }
       ...
    }
    

    相关文章

      网友评论

          本文标题:Retrofit使用与分析

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