使用
众所周知,Retrofit只是对OkHttp的一层封装,目的是为了让OkHttp使用起来更便捷。主要就是对Request对象的构建进行了一层封装,使我们只需要定义好借口的形式就OK,使用起来更偏向方法的直接调用(结合协程)。然后是对Call进行了包装对返回结果进行了处理,加入了解析器,可以直接返回我们所需要的对象。
依赖
1
2
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
这里引入的Retrofit中自动包括了OkHttp,所以不需要我们再单独引入了。另外引入了一个gson的json解析器,是常用来解析json的。
创建Retrofit对象
1
2
3
4
5
val retrofit = Retrofit.Builder()
.baseUrl("https://coding.jiangker.cn")
.client(OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build()
Retrofit和之前的OkHttp类似的,都是用来做统一管理的,这里也可以自己定义OkHttpClient,不过一般都是保持默认,默认也是使用的OkHttpClient所以可以省略。
构建请求接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface RetrofitService {
@GET("demo")
fun getUser(
@Query("name") name: String,
@Query("age") age: Int
): retrofit2.Call<User>
@GET("demo")
suspend fun syncGetUser(
@Query("name") name: String,
@Query("age") age: Int
): User
}
val service = retrofit.create(RetrofitService::class.java)
@Query注解可以相当于往后拼接params参数。常有的还有@Path、@Header、@Body等。对于常规方式是直接返回retrofit2.Call这个对象,较Okhttp的Call对象有更多的能力,但实际发起请求还是依赖OkHttp的call。对于使用kotlin协程的来说,可以直接添加suspend然后直接返回需要的结果。 然后直接使用Retrofit来创建相关接口的服务器对象。
发起请求
call请求
1
2
3
4
5
6
7
8
9
10
11
12
13
userCall.execute()
userCall.enqueue(object :retrofit2.Callback<User>{
override fun onResponse(
call: retrofit2.Call<User>,
response: retrofit2.Response<User>
) {
// 默认主线程返回
}
override fun onFailure(call: retrofit2.Call<User>, t: Throwable) {
// 默认主线程返回
}
})
可以看出基本上用法和OkHttp一致,这里的切换回主线程经过了一次调度器。可以使用@SkipCallbackExecutor注解去跳过
协程请求
1
2
3
val user: User = withContext(Dispatchers.IO) {
service.syncGetUser("jiangker", 18)
}
协程请求看着形式上会比普通的call请求更简单,这里请求实际是使用的execute()发起的,所以需要手动去切换子线程。这里对错误结果也没有进行处理的,一般需要进行catch处理。
原理
Retrofit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public final class Retrofit {
// 接口方法缓存
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
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);
}
});
}
// 检验传入接口的有效性
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
// 是否直接解析所有接口,默认是false的
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
// 方法解析
ServiceMethod<?> loadServiceMethod(Method method) {
// 查找是否已经解析过了
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
}
Retrofit中有比较多的基础配置,create方法对传入的方法进行动态代理,返回一个接口的代理对象,对方法的解析可以设置为饿汉的形式直接解析全部,也可以是用到一个解析一个。解析是用到了ServiceMethod去进行具体的解析,解析的结果也会缓存到Retrofit的map中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//serviceMethodCache.java
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.");
}
// 生成请求CallAdapter等
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory中保存着解析后的所有结果,在build方法中进行真正的解析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod;
private final @Nullable String relativeUrl;
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
// 是否是协程
final boolean isKotlinSuspendFunction;
}
可以看出RequestFactory中有一个参数表示是否是协程请求,这个参数是在build过程中确定的,是根据最后一个参数是否为Continuation确定的。
再回头看看解析过程HttpServiceMethod.parseAnnotations的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
// 这里会包装成为type为Call
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
// 因为协程不需要切换线程,所以确保有跳过注解
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
// 创建Retrofit的通用CallAdapter,由CallAdapter.Factory创建,返回的是由DefaultCallAdapterFactory创建的匿名内部类
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
// ...
// 创建解析器
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
// 区别是是否需要Response来包裹
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
主要是创建CallAdapter,这里会根据是是否是协程生成普通的HttpServiceMethod还是SuspendForBody这个HttpServiceMethod。关系如下:
请求部分
首先线看一下Call的实现类有哪些
这里有两个类都实现了Retrofit的Call接口,ExecutorCallbackCall主要是一个代理类,为需要返回结果线程调度的类提供一个线程调度。而OkHttpCall才是真正对OkHttp的Call的封装,里面实现了真正的Call的创建和请求等。
然后再看一下创建方法时候的动态代理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
// ...
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
在方法解析完成后直接调用了其的invoke方法
1
2
3
4
5
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
invoke方法创建了真正的OkHttpCall
最后再调用了adapt方法,这里因为HttpServiceMethod的具体实现类不同,所以后面再看
普通请求
接着一般请求的adapt方法
1
2
3
4
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
这个callAdapter由Retrofit创建,实际是由DefaultCallAdapterFactory返回的一个匿名内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 对call的代理,主要是返回结果切换线程
if (getRawType(returnType) != Call.class) {
return null;
}
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
// 切换回主线程
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
}
}
这里的代码比较简单,DefaultCallAdapterFactory内部传入了callbackExecutor来对结果切换线程,在安卓中是主线程的调度器。adapt方法在调用时会根据是否需要切换线程,然后默认的call对象还是有线程调度的call代理。
1
2
3
4
5
6
7
8
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
使用handler来制作的调度器。
execute
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
// 这里会创建一个真正的call请求对象
call = getRawCall();
}
if (canceled) {
call.cancel();
}
// 触发请求并解析结果
return parseResponse(call.execute());
}
因为阻塞请求是不需要调度的,所有跳过那款代码,直接看最后的部分。流程比较简单,就是创建一个OkHttp的call对象,然后执行请求,最后解析结果。
enqueue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(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 {
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) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@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) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
和同步请求类似,都是创建OkHttp的Call对象,利用OkHttp来发起真正的请求。
协程请求
协程请求不同与普通的请求,因为方法调用时结果就返回了,而不是通过Call去调用的。所以实际的请求是在解析后直接执行的,那么奥秘就是在adapt方法中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
try {
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
可以看出一样是使用callAdapter来构建出真实的请求类,实际返回的也是他本身,然后使用协程启动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
suspend fun <T : Any> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
// 调用call的enqueue方法启动
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)
} else {
continuation.resume(body)
}
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
这里和正常的协程调用的是一个enqueue,只是这里并不包含切换线程的代理。
总结:
- Retrofit在create方法时,会为接口生成一个动态代理,在方法调用时开始解析方法。
- 解析过程会根据参数是否有Continution区分是否是协程请求,过程会得到一个由DefaultCallAdapter创建的CallAdapter对象,然后构建到解析好的方法中。CallAdapter主要用作适配是否需要线程调度。默认调度器是使用Handler实现的。
- 创建的方法返回后,会触发invoke方法,方法中都会创建一个OkHttpCall对象,这个对象是真正对Okhttp的Call的封装。然后使用之前的调度器CallAdapter进行代理返回一个被代理的Call。
- 方法的触发就是直接调用Call的方法,然后在对应的方法中会执行OkHttp Call的构建以及真实的请求,对请求回来的数据然后进行解析。对于协程来说,在解析方法后的invoke转换中就会利用Call的扩展函数来进行协程的请求。