Retrofit 是什么?
Retrofit
担任将Http
的API
接口转化为Java
接口,它是一个RESTful
风格的Http
网络恳求结构的封装,实际上的网络恳求仍是由OkHttp
完结,Retrofit
仅担任网络接口恳求的封装。
- App 中经过
Retrofit
恳求网络,实际上是运用Retrofit
接口层封装恳求参数、Header
、Url
等信息,之后由OkHttp
完结后续的恳求操作。 - 在服务端回来数据之后,
OkHttp
将原始的成果交给Retrofit
,Retrofit
依据用户的需求对成果进行解析。
所以,网络恳求的本质仍旧是 OkHttp
完结的,Retrofit
仅仅帮运用者来进行作业简化的,比方配置网络,处理数据等作业,进步这一系列操作的复用性。
如何运用 Retrofit
?
- 引入依赖
implementation 'com.squareup.okhttp3:okhttp:+'// OkHttp网络库
implementation 'com.squareup.retrofit2:retrofit:+'// retrofit库
implementation 'com.google.code.gson:gson:+'// gson生成和解析库
implementation 'com.squareup.retrofit2:converter-gson:+'//Gson转化器,恳求成果转化为数据Model
implementation 'com.squareup.retrofit2:adapter-rxjava2:+'// 配合Rxjava运用
implementation 'io.reactivex.rxjava3:rxjava:+'//
implementation 'io.reactivex.rxjava3:rxandroid:+'//一个帮助做异步恳求的结构,类似于AsyncTask
- 创立
API
恳求接口
Retrofit
将Http
恳求抽象成Java
接口:采用注解描述网络恳求参数和配置网络恳求参数
//自己界说的 API 恳求接口
interface MyApiService {
@GET("{source}/media/list")
fun getMediaList(@Path("source") source: String): Call<List<Media>>
}
- 创立
Retorfit
实例,并发送恳求
//1. 创立Retrofit实例
val retrofit = Retrofit.Builder()
.baseUrl("http://api.test.com/") //设置网络恳求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.build()
//2. 创立MyApiService目标
val apiService = retrofit.create(MyApiService::class.java)
//3. 获取Call目标
val mediaList = apiService.getMediaList("qqm")
//4. 调用call.enqueue建议异步恳求
mediaList.enqueue(object: Callback<List<Media>> {
override fun onResponse(call: Call<List<Media>>, response: Response<List<Media>>) {
Log.d(TAG, "mediaList response code is ${response.code()}")
}
override fun onFailure(call: Call<List<Media>>, t: Throwable) {
Log.e(TAG, "mediaList failure")
}
})
Retrofit 的中心概念
注解
Retrofit
运用注解来描述 HTTP
恳求的参数、URL
和恳求办法。以下是常见的注解:
-
@GET
:发送GET
恳求 -
@POST
:发送POST
恳求 -
@Path
:替换URL
中的参数 -
@Query
:增加查询参数 -
@Body
:发送恳求体
public interface ApiService {
@GET("posts/{id}")
Call<Post> getPostById(@Path("id") int postId);
}
CallAdapter
-
CallAdapter
主要用于将Retrofit
的Call
类型适配到其他类型,例如LiveData
、RxJava
的Observable
等,Retrofit
内置了常见的CallAdapter
,如RxJavaCallAdapter
和LiveDataCallAdapter
- 运用场景: 当你希望在进行网络恳求时,直接得到一个特定类型的呼应,而不是
Retrofit
默许的Call
类型时,就能够运用CallAdapter
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
Converter
- 作用:
Converter
主要用于将恳求体和呼应体进行转化,将网络恳求的原始数据转化为你需求的实体目标,以及将实体目标转化为网络恳求的原始数据。 - 运用场景: 当你需求自界说恳求体和呼应体的转化逻辑时,能够运用
Converter
。 - 示例: 假如你的服务器回来的是 JSON 数据,你能够运用
GsonConverterFactory
将 JSON 数据转化为 Java 目标。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
源码分析
触及到的类及重要办法
-
IMyApiService
:自界说的API
接口,经过注解声明网络恳求 -
Retrofit
:经过内部Builder.build
构建-
create
办法:经过动态署理,生成IMyApiService
的署理类; -
loadServiceMethod
办法:ServiceMethod
能够浅显的理解为咱们在API
接口中界说的办法完成,loadServiceMethod
办法调用缓存或新建的ServiceMethod
实例
-
-
ServiceMethod
:能够浅显的理解为咱们在API
接口中界说的办法完成,但它是一个类-
parseAnnotations
办法:创立RequestFactory
实例,并调用HttpServiceMethod.parseAnnotations
回来ServiceMethod
实例。
-
-
HttpServiceMethod
:承继自ServiceMethod
-
parseAnnotations
办法:解析注解的办法,获取所有注解,内部继续调用createCallAdapter
,创立CallAdapter
目标,最终回来CallAdapted
内部类或者SuspendForResponse
内部类(kotlin 协程调用),这两个内部类都承继自HttpServiceMethod
,均包含requestFactory
/callFactory
/responseConverter
/callAdapter
-
-
Call/OkHttpCall
:Retrofit
结构内的Call
接口,非OkHttp
内部的Call
:-
public interface Call<T> extends Cloneable { Response<T> execute() throws IOException; void enqueue(Callback<T> callback); boolean isExecuted(); void cancel(); boolean isCanceled(); Call<T> clone(); Request request(); Timeout timeout(); }
-
Call
内部根本上和OkHttp3.Call
接口一致,有同步履行办法execute
,也有异步网络恳求办法enqueue
,这个Call
接口的完成是 ****OkHttpCall
-
Retrofit.create
retrofit2.Retrofit#create
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);
}
});
}
在 create
办法中,运用动态(运行期)署理,完成自界说 API 接口的详细代码:
-
经过
Proxy.newProxyInstance
创立IMyService
的动态署理完成类; -
当咱们调用
apiService.getMediaList("qqm")
办法时,完成类内部会调用 ****InvocationHandle
****拦截到对应的办法和参数信息,调用invoke
办法 -
在
invoke
办法中,调用loadServiceMethod.invoke
,这个办法会获取API
办法上的注解,去拼成一个正常的OkHttp
恳求
retrofit2.Retrofit#loadServiceMethod
ServiceMethod<?> loadServiceMethod(Method method) {
//1.
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//2.
result = ServiceMethod.parseAnnotations(this, method);
// 3.
serviceMethodCache.put(method, result);
}
}
return result;
}
-
从缓存
ConcurrentHashMap
中获取ServiceMethod
; -
经过
ServiceMethod.parseAnnotations(this,method)
,新建ServiceMethod
目标; -
将新建的
ServiceMethod
实例放入缓存ConcurrentHashMap
中,以便下次复用
ServiceMethod.parseAnnotations
retrofit2.ServiceMethod#parseAnnotations
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 1.
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
// 2.
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
-
经过
RequestFactory.parseAnnotations(retrofit,method)
办法新建RequestFactory
实例,-
RequestFactory
能够看成是Retrofit
结构中构建OkHttp
恳求的工厂类,其间包含一个create
办法,用于创立OkHttp
的request
-
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;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException(
"Argument count ("
+ argumentCount
+ ") doesn't match expected count ("
+ handlers.length
+ ")");
}
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]);
}
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
-
parseAnnotations
:调用内部Builder.build
办法,去解析API
办法上的注解,解析包含是GET
仍是POST
办法,Header
有什么,恳求链接是什么等,将其赋值给Builder
内的headers/method/contentType
等变量,用于后续构建恳求体
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();
}
// retrofit2.RequestFactory.Builder#build
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
-
HttpServiceMethod.parseAnnotations(retrofit,method,requestFactory)
新建HttpServiceMethod
实例(承继自ServiceMethod
)
调用 HttpServiceMethod.parseAnnotations
,并将对应的 Retrofit/Method/RequestFactory
目标传入:
// retrofit2.HttpServiceMethod#parseAnnotations
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]);
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<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
// 1.
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
// 2.
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
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);
}
}
-
经过
retrofit
获取okhttp3.Call.Factory
目标,实际上便是OkHttpClient
实例 -
假如不是
Kotlin
的suspend
函数,回来CallAdapted
目标(HttpServiceMethod
的子类),不然回来SuspendForBody
目标(同样是HttpServiceMethod
的子类)
HttpServiceMethod.invoke
追寻了一连串的源码,咱们经过 loadService
办法取得了 HttpServiceMethod
,而后调用其invoke
办法:
@Override
final @Nullable ReturnT invoke(Object[] args) {
//1. 新建OkHttpCall实例
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//2.
return adapt(call, args);
}
-
新建
OkHttpCall
实例,参数包含前述步骤创立的RequestFactory
实例,OkHttpClient
,呼应转化器以及恳求参数; -
调用
adapt(call,args)
办法回来调用成果,该办法有多个完成,咱们以CallAdapted
类为例进行说明:-
// retrofit2.HttpServiceMethod.CallAdapted#adapt @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); }
-
调用 callAdapter.adapt(call)
,没有增加 CallAdapter
时,运用默许的CallAdapter.adapt
:
//retrofit2.CallAdapter#adapt
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
回来ExecutorCallbackCall
实例。
至此,就完结了 apiService.getMediaList
的调用
接着,咱们调用 Call.enqueue
,即ExecutorCallbackCall.enqueue
:
Call.enqueue
//retrofit2.DefaultCallAdapterFactory.ExecutorCallbackCall#enqueue
@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));
}
});
}
整个调用仍是经过 delegate.enqueue
,即 OKHttpCall.enqueue
办法完结:
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 {
// 1.
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 2.
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
}
}
});
}
- 经过
createRawCall
创立OkHttp3
的Call
实例:
//retrofit2.OkHttpCall#createRawCall
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
经过 callFactory
(即 OkHttpClient
)创立 RealCall
目标,即 OkHttp
根本运用的流程。
-
得到
RealCall
目标后,调用RealCall.enqueue
办法,得到呼应成果,并在OkHttp
的Callbak
中,调用Retrofit
中的Callback
至此,整个 Retrofit
的网络恳求完结
总结
用户界说注解接口,用于声明Http
恳求,而Retrofit
经过动态署理生成注解接口的署理类,用户建议API
调用时,会经过动态署理完成类中的InvocationHandler
类中的invoke
办法中,调用loadServiceMethod.invoke
,这个办法会获取 API
办法上的注解,去拼成一个正常的 OkHttp
恳求,在这个过程中,触及:
-
RequestFactory
:构建OkHttp
Request
的工厂类,其间包含parseAnnotations
办法用于解析注解; -
HttpServiceMethod
:能够经过HttpServiceMethod.invoke
取得HttpServiceMethod
实例,而后调用其invoke
办法,invoke
办法中构建OkHttpCall
实例,并回来ExecutorCallbackCall
恳求成果,咱们调用ExecutorCallbackCall.enqueue
取得回来成果; -
Call.enqueue
:其实是OkHttpCall.enqueue
的包装,包含回来成果的回调也是对OkHttpCall
回调的包装;