1. Retrofit是怎么将回调函数放到主线程的?
看new Retrofit.Builder()的Builder方法
当返回对象为Call,就会使用默认的DefaultCallAdapterFactory
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) {
checkNotNull(callback, "callback == null");
//也就是在这里执行网络请求后,线程转换了
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
// 这里的callbackExecutor就是上图中的mainThreadExecutor
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
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(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
2 retrofit的初始化
2.1 .build()方法干了写什么?
//new Retrofit.Builde().build()方法
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 配置回调方法执行器(callbackExecutor)-
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//配置网络请求适配器工厂(CallAdapterFactory)
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//CompletableFutureCallAdapterFactory中包含BodyCallAdapter与ResponseCallAdapter(后面会讲到)
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));//注意Android extends Platform
//配置数据转换器工厂:converterFactory
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 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);
converterFactories.addAll(platform.defaultConverterFactories());
//也就是将开始将的handler、defaultCallAdapterFactories与自己添加的CallAdapterFactories、默认的converterFactorie与添加的converterFactories存起来了
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位-末位开始遍历,因此集合中的工厂位置越靠前就拥有越高的使用权限
callAdapterFactories里面的callAdapter中包含了执行网络请求的call对象,那么用哪个call去执行网络请求呢?匹配规则
RxJava2CallAdapterFactory:对应返回值Observable
CompletableFutureCallAdapterFactory:如果返回值是Response -> BodyCallAdapter 否则 ResponseCallAdapter
DefaultCallAdapterFactory: 对应返回值为Call,也就是纯retrofit的时候就是它了
BuiltInConverters: 返回类型为ResponseBody、Void、Unit
OptionalConverterFactory: Java8的新特性,Optional.ofNullable(delegate.convert(value)) 避免空指针的
2.2 .create()方法中的loadServiceMethod(method).invoke()方法
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();
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);
}
if (platform.isDefaultMethod(method)) { //java8 后接口可以写默认方法
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//关键是看这两个方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
先看loadServiceMethod()方法:
ServiceMethod.parseAnnotations(this, method);
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
//比如这样的一个接口
@POST
fun getLiveRoomUserSig(@Url url: String, @Body body: HashMap<String, String>): Observable<HttpResponse<JBLiveRoomUserSigModel>>
methodAnnotations:POST 也就是方法上的注解
parameterTypes: String 与 HashMap 也就是方法参数类型
parameterAnnotationsArray:URL 与 Body 也就是方法的参数注解
这里我们需要关注下对parameterAnnotationsArray的处理,也就是将我们的参数(比如map)转换成发起网络请求的数据
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation); //请求方式 POST Get等 的处理
}
...省略部分代码
//方法上的参数注解处理,比如常用的:@FieldMap @Body
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
//需要注意 这里 方法参数注解 与 方法参数类型 是 一一匹配的 不同的是parameterAnnotationsArray是个二维数组,因为一个参数可能有多个注解
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
//annotations就是上面说的多个注解,这里遍历如果一个参数找到多个Retrofit批注 就抛异常了
if (result != null) {
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
//紧接着 parseParameterAnnotation 跟进来 这里我们看下常用的
if (annotation instanceof Body) {
Converter<?, RequestBody> converter;
try {
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(method, e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
return new ParameterHandler.Body<>(method, p, converter);
}else if (annotation instanceof FieldMap) { //比如 @FormUrlEncoded 的时候 用的这个,
if (!isFormEncoded) { //可见如果用FieldMap 而不是isFormEncoded的请求方式,就抛异常了
throw parameterError(method, p,"@FieldMap parameters can only be used with form encoding.");
}
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
//默认得到的是 BuiltInConverters.ToStringConverter.INSTANCE
return new ParameterHandler.FieldMap<>(method, p,
valueConverter, ((FieldMap) annotation).encoded());
}
解析完后将每个参数对应的ParameterHandler 都保存到了 parameterHandlers数组中, 再创建RequestFactory对象
也就是说:上面拿到了对请求体的解析,对网络请求前做处理
这里需要注意一个方法:RequestFactory类中有个create()方法,如下图,返回了一个okhttp3.Request对象
在哪里调用?
继续看这个方法在哪些地方调用了:
看方法名,很明显这都是在执行网络请求的时候调用的,也是真正执行网络请求的地方。
图中createRawCall()方法三个调用的地方稍后再做具体分析,先看下requestFactory.create()方法干了些啥
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;//args 就是参数的个数,retrofit代理那块传过来的
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
if (isKotlinSuspendFunction) {
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);//遍历parameterHandlers 执行apply方法,为requestBuilder设置请求体
}
//再使用requestBuilder构建网络请求的Request对象
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
继续上面代码的执行流程,就到了下面这个方法,这里就对应了响应数据与网络请求相关的处理:
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[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
//ParameterizedType 代表是 参数化类型,简单点说 就是responseType是一个带泛形的类
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//获取相匹配的callAdapter 该callAdapter做了啥? 看下图
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// 拿到的responseType是啥? 看下图 当配合RxJava2CallAdapterFactory时,
// adapterType = Observable<T> responseType就是我们Observable<T> 的T的类型
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
//根据需要的返回类型,来匹配对网络请求成功的json数据的解析类 具体看下图, 最后返回了GsonResponseBodyConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//如果返回的类型不是 Suspend 函数 就会返回CallAdapter, 比如当我们使用Rxjava2Adapter时,定义的接口返回的Observable
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
//如果是 Suspend 函数, 判断方法返回值是不是Response
return (HttpServiceMethod<ResponseT, ReturnT>) 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);
}
}
上面调用createCallAdapter 打了个断点,可看到createCallAdapter方法里的参数信息如下
再跟下去,
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter; //如果我们使用的Rxjava+Retrofit的模式,那么根据上面中的参数,匹配上的CallAdapter就是RxJava2CallAdapter了
}
}
上面返回adapter后,紧接着获取接口请求后的返回类型callAdapter.responseType();
response转换器的创建过程
也就是说loadServiceMethod(method)该方法主要是创建并加载ServiceMehod,用于解析网络请求接口参数、网络请求适配器、response数据解析器的工作。
2.3. 返回HttpServiceMethod后就调用.invoke()方法,返回OkhttpCall对象
requestFactory 里面包含请求方式、请求Url、请求体
callFactory 为OkhttpClient对象
responseConverter 为我们的json转换,比如GsonConverterFactory
然后将这些数据都放到OkHttpCall中(OkHttpCall<T> implements Call),这里面有两个方法,用来执行网络请求:同步请求execute() 与异步请求 enqueue()
这两个方法在哪里开始执行的呢?以RxJava2CallAdapter为例,所以上图中adapter对应的来到
点击去就可以看到在subscribeActual()方法中执行了对应的请求,
点击call.execute(),就来到了OkHttpCall的execute()
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (call == null) {
try {
call = rawCall = createRawCall(); //这里也就是上文所指的稍后分析的问题了
} catch (IOException | RuntimeException | Error e) {
}
}
}
return parseResponse(call.execute()); //解析请求成功后的数据
请求成功后,调用GsonResponseBodyConverter的convert()方法,返回我们需要的实体类,
OkHttpCall - > parseResponse
并且还可以发现取消网络请求的操作也在CallExecuteObservable里面。
那么如果是用协程配合retrofit,网络请求又是怎么取消的呢?
//当只使用Retrofit的时候,接口是这样定义的 返回Call
@GET("article/list/1/json")
fun getHomeList() : Call<BaseResponse<Data>>
//当使用协程与Retrofit配合使用的时候,方法上加了个suspend
@GET("article/list/1/json")
suspend fun getHomeList() : BaseResponse<Data>
//发起网络请求
viewModelScope.launch {
withContext(Dispatchers.IO) { getHomeList() }
}
3. 为啥使用viewModelScope,能自动取消网络请求呢?
当使用这种模式的时候,网络请求发起的包装类为:SuspendForBody (上面有提到哟)
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
SuspendForBody(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter, boolean isNullable) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
this.isNullable = isNullable;
}
@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
//OkHttp Call.enqueue()带有异常,协程将拦截Continuation的后续调用
try {
return isNullable //为false
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.yieldAndThrow(e, continuation);
}
}
}
再往下走
suspend fun <T : Any> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel() //取消网络请求
}
enqueue(object : Callback<T> { //发起网络请求 这里是OkHttpCall的enqueue方法
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的执行,这里执行了Call类中的enqueue方法,并拿到返回值,通过continuation把结果和异常统统返回给协程的调用者。
continuation:顾名思义,继续、持续的意思,协程中的类,表示一个协程的延续,协程执行的时候会挂起,这个类就用于挂起完成之后的后续工作,看起来相当于一个回调。
继续跟进查看OkHttpCall的enqueue方法
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);//将网络请求成功后的Response转换成我们的实体类
} 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
}
}
流程图: