官网:https://square.github.io/retrofit/
参考:https://blog.youkuaiyun.com/lmj623565791/article/details/51304204
1.基本使用
(1)定义一个API接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
(2)初始化一个Retrofit,创建API接口的实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
(3)调用具体的接口方法
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
2.基本API介绍
(1)@GET:get请求,参数是接口地址,和创建Retrofit时传入的baseUrl一起组成完整的请求地址
(2)@Path:以参数的形式动态组成接口地址
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
(3)@Query:get请求的参数
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
(4)@POST:post请求,参数是接口地址,和创建Retrofit时传入的baseUrl一起组成完整的请求地址
@POST("users/new")
Call<User> createUser(@Body User user)
(5)@Body:post请求的入参
@POST("users/new")
Call<User> createUser(@Body User user)
(6)@FormUrlEncoded,@Field:表单形式请求
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
(7)@Multipart,@Part:文件上传,多个请求体
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
(8)@Headers,@Header,@HeaderMap:请求头
@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)
(9)addConverterFactory:可以对请求体和返回参数进行处理,比如请求格式都是json就可以使用GsonConverterFactory
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
除了json还支持其他格式
- [Gson]: `com.squareup.retrofit2:converter-gson`
- [Jackson]: `com.squareup.retrofit2:converter-jackson`
- [Moshi]: `com.squareup.retrofit2:converter-moshi`
- [Protobuf]: `com.squareup.retrofit2:converter-protobuf`
- [Wire]: `com.squareup.retrofit2:converter-wire`
- [Simple XML]: `com.squareup.retrofit2:converter-simplexml`
- Scalars (primitives, boxed, and String): `com.squareup.retrofit2:converter-scalars`
注意:用到哪个必须先引用相应的库
3.源码初步解析
从基本使用方法进行分析,下面是个人绘制的一个流程图,结合流程图来分析会更直观
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
1.创建Retrofit
(1)new Retrofit.Builder()
这个方法主要是创建了Platform
public Builder() {
this(Platform.get());
}
具体创建代码如下:
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
我们这里只讨论Android平台,可以看下Android这个类里面都包含了些什么
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
可以看到这里提供了一个默认执行器MainThreadExecutor和网络请求适配器ExecutorCallAdapterFactory
(2).build()
看下Retrofit创建的具体代码
public Retrofit build() {
//网络请求地址
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//Okhttp请求
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//执行者
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//如果为空取之前platform创建的
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//网络请求适配器列表
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加默认的适配器,也是从platform获取的
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//转换器列表
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
//添加默认的转换器
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
这里构建了很多重要的参数
- okhttp3.Call.Factory:用于okhttp请求,我们都清楚retrofit真正网络请求部分是通过okhttp实现的
- HttpUrl:请求地址,由baseUrl传入
- List<Converter.Factory>:转换器列表
- List<CallAdapter.Factory>:适配器列表
- Executor:执行者
- validateEagerly(Boolean):目前还不清楚有什么用
2.创建API接口的实例retrofit.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);
}
});
}
这里使用了Java动态代理的方法,简单来理解就是动态代理额外帮我们处理了很多事情,这里就把接口的方法转换成具体的请求,其中最重要的是最后三句话,下面一一进行分析。
(1)loadServiceMethod(method),创建ServiceMethod
public ServiceMethod build() {
//创建适配器,会遍历之前的适配器列表
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//创建转换器,会遍历之前的转换器列表
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//处理请求参数
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
上面的代码主要做了以下几点:
- 创建适配器,遍历Retrofit里的适配器列表,成功就返回,所以定义适配器的顺序很重要,不过目前适配器应该比较少自己定义主要还是结合RxJava的RxJavaCallAdapterFactory使用
- 创建转换器,遍历Retrofit里的转换器列表,也是成功就返回
- 处理请求参数
(2)new OkHttpCall<>(serviceMethod, args)
初始化OkHttpCall,代码比较简单就不贴出来了
(3)serviceMethod.adapt(okHttpCall)
调用适配器的adapt方法,适配器在创建ServiceMethod中已经定义了
3.网络请求部分
这里只分析异步请求,Call.enqueue方法,实际调用的是OkHttpCall的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//创建了okhttp,主要请求也是通过okhttp实现的
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//具体的请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//使用转换器对返回数据进行处理
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
//结果进行回调
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
- 创建了OkHttp.Call
- 调用OkHttp的请求方法
- 使用转换器对返回值进行处理
- 将结果进行回调
4.总结
- Retrofit是一个优秀的第三方框架,使用了很多设计模式对代码进行封装,解耦,建造者模式,适配者模式,动态代理,工厂模式,策略模式等,很值得我们学习
- 用户可以使用addConverterFactory和addCallAdapterFactory对代码进行定制化的处理