RxJava + Retrofit怎麼請求網路,具體的用法這裡就不講了,本文只講一些重點原始碼。
版本如下:
okhttp : "com.squareup.okhttp3:okhttp:3.10.0",
okhttp3_integration : "com.github.bumptech.glide:okhttp3-integration:1.4.0@aar",
retrofit : "com.squareup.retrofit2:retrofit:2.4.0",
converter_gson : "com.squareup.retrofit2:converter-gson:2.3.0",
converter_scalars : "com.squareup.retrofit2:converter-scalars:2.3.0",
converter_protobuf : "com.squareup.retrofit2:converter-protobuf:2.3.0",
adapter_rxjava2 : "com.squareup.retrofit2:adapter-rxjava2:2.2.0",
logging_interceptor : "com.squareup.okhttp3:logging-interceptor:3.10.0",
rxjava : "io.reactivex.rxjava2:rxjava:2.1.12",
rxandroid : "io.reactivex.rxjava2:rxandroid:2.0.2",
一、首先關於Retrofit的初始化:
private void initRetrofit() {
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl) //設定地址
.client(client.build()) //設定自定義的OkHttpClient
.addConverterFactory(ProtoConverterFactory.createWithRegistry(extensionRegistry))
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(buildGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
service = retrofit.create(ApiService.class);
}
.addConverterFactory(ProtoConverterFactory.createWithRegistry(extensionRegistry))
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(buildGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
新增了資料轉換器與請求介面卡。
Retrofit的初始化採用了Builder模式。
Retrofit.Builder()這一步,獲取了一個平臺,肯定就是Android()了,後面有地方會用到。
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
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();
}
}
在看最後的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();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
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);
}
1、如果沒有傳入我們自定義的OkHttpClient,那麼便會使用預設的。
2、如果沒有設定自定義的回撥執行器,那麼便會是用預設的platform.defaultCallbackExecutor();點進入可以發現回撥是預設在主執行緒中的:
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);
}
}
}
3、把我們設定的請求介面卡新增進入,然後再新增一個預設的請求介面卡。
4、新增進入一個預設的資料轉換器,然後再被我們設定的資料轉換器新增進去。
二、初始化好Retrofit後,再來看這一句:
service = retrofit.create(ApiService.class);
ApiService是一個介面,裡面方法如下:
@GET
Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);
這個create方法可以說是核心,它運用的是動態代理。
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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);
}
});
}
1、首先檢測這是否是一個介面,只有介面才能對它進行動態代理。
2、是否需要對介面裡面的方法進行初始化預載入,是的話便進行,這個與下面的有點重複,直接講下面的。
3、return後面的語句便是動態代理的地方,它會代理介面的所有方法,也就是說,當我們呼叫ApiService的方法的時候,會被攔截,然後走到inoke這個方法做我們自己的操作。
關於動態代理,後面會單獨講。
4、接下來邊看invoke方法:
(1)、首先判斷該方法是否為Object這個類的方法,如果是,不攔截它,讓他走原來的方法。
(2)、platform為Android,platform.isDefaultMethod(method)返回false,不用管它。
(3)、ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);拿到介面的方法,對介面的方法進行解析,比如獲取註解,引數之類,構造自己的serviceMethod
(4)、初始化OkHttpCall
(5)、呼叫serviceMethod.adapt(okHttpCall)進行請求(因為採用的是RxJava,所以這裡並不會立即請求,只有被訂閱的時候才會,等會會講)
三、loadServiceMethod(method)方法:
構造自己的serviceMethod 也採用了Builder模式。
進入這個方法後,重點的一句:
result = new ServiceMethod.Builder<>(this, 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();
}
注:我們這裡以前面定義的方法來講解:
@GET
Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);
1、持有retrofit與原始的method物件。
2、獲取方法上的註解,獲取到的為:
3、獲取引數型別,獲取到的為:
4、獲取引數上面的的註解,獲取到的為:
再看build()方法:
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);
}
1、首先獲取請求介面卡。
2、建立請求結果的轉換器。
3、對方法上的註解進行解析。
4、構造ParameterHandler陣列。
5、對一些異常的判斷。
四、我們接下來對每一步進行講解。
1、首先獲取請求介面卡:
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
(1)、獲取方法的返回型別,返回型別不能是void
(2)、獲取方法上的註解。
(3)、呼叫retrofit.callAdapter(returnType, annotations)方法獲取請求的介面卡。(我們之前設定的請求介面卡都在retrofit物件中)
裡面關鍵的一步為:
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;
}
}
skipPast為null,所以start為0;
遍歷我們之前設定給它的請求介面卡,根據返回型別與方法上的註解去找,找到了便返回。(我們這裡獲取到的callAdapter為RxJava2CallAdapter)
2、建立請求結果的轉換器:
responseConverter = createResponseConverter()
這個與獲取請求的介面卡的過程是類似的,因此這裡就略過了。
3、解析方法上的註解:parseMethodAnnotation(annotation),我們用的是GET,所以下面會呼叫:
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
我們這裡value是空的,所以它只走了下面這些就返回了。
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
4、構造ParameterHandler陣列
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);
}
主要是這一個方法:
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
p為序號,parameterType為方法的引數型別,parameterAnnotations為引數的註解。
裡面就不細講了,這裡最終得到的是:
對於一些異常的判斷就不多講了,比如:
不能有多個帶@Url註解的引數。
不能同時使用@Path與@Url註解。
被@QueryMap標註的引數型別必須是Map
@QueryMap註解的引數的key必須是String
至此,我們的ServiceMethod便構造完了。
五、我們回到代理的那個方法裡面,還差兩句沒有解析:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
主要看serviceMethod.adapt(okHttpCall)
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
這裡的callAdapter是RxJava2CallAdapter。
於是我們來到它的adapter方法:
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
首先我們看isAsync,這裡為false,為什麼呢?我們建立adapter的時候是這樣的:
RxJava2CallAdapterFactory.create()
public static RxJava2CallAdapterFactory create() {
return new RxJava2CallAdapterFactory(null, false);
}
第二個引數便是isAsync
1、所以我們建立的responseObservable為CallExecuteObservable<>(call),(同步執行的類)
2、我們建立一個Observable<?> observable,這裡建立的是BodyObservable<>(responseObservable),將剛剛建立的responseObservable
傳進去。
3、最終將該observable傳出去。
service = retrofit.create(ApiService.class);
public interface ApiService {
@GET
Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);
}
service.doGet(url, header, params?.params)
也就是說,當我們呼叫service.doGet的時候,會走到代理的invoke方法,然後返回一個Observable
而該Observable只有在被訂閱的時候才會執行,而且我們用的是同步,所以還需要在外面自己切換到子執行緒執行。
當被訂閱的時候,該BodyObservable會呼叫subscribeActual:
BodyObservable(Observable<Response<T>> upstream) {
this.upstream = upstream;
}
@Override protected void subscribeActual(Observer<? super T> observer) {
upstream.subscribe(new BodyObserver<T>(observer));
}
而這個upstream便是剛剛傳進去的responseObservable,呼叫subscribe方法,最終會執行到responseObservable的subscribeActual方法。
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
observer.onSubscribe(new CallDisposable(call));
boolean terminated = false;
try {
Response<T> response = call.execute();
if (!call.isCanceled()) {
observer.onNext(response);
}
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!call.isCanceled()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
我們主要看Response<T> response = call.execute();call便是我們傳進來的自定義的OkHttpCall
在call.execute()裡面:
.
.
.
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
.
.
.
return parseResponse(call.execute());
createRawCall()獲取okhttp3.Call,call.execute()便是okhttp的網路請求了。
我們主要看怎麼獲取okhttp3.Call,以及對請求結果的解析parseResponse方法。
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
ServiceMethod裡面:
/** Builds an HTTP request from method arguments. */
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
方法主要是構造了request然後使用okhttp3.Call.Factory建立okhttp3.Call,而我們之前在構建ServiceMothod的構造的ParameterHandler<Object>[] handlers便參與了request的構建,主要是將之前解析到的引數,比如路徑,頭部資訊等新增到request裡面。
再看一下請求結果的解析parseResponse方法:
重點語句:
T body = serviceMethod.toResponse(catchingBody);
在看serviceMethod裡面的toResponse方法:
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
這裡便用到了我們之前設定的資料轉換器,對結果進行轉換。
以上便是大概的過程了。
轉載請標明:https://www.cnblogs.com/tangZH/p/13723480.html