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()
方法,它的重点再最后三个语句
- 通过相应的
method
的参数和注解包装出一个ServiceMethod
- 通过这个
ServiceMethod
创建出一个OkHttpCall
-
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);
}
...
}