RxJava+Retrofit2搭建網路請求元件完整配置、示例程式碼及流程梳理
本文是對之前寫的兩篇文章的綜合概述及全流程梳理
Android 利用RxJava和Retrofit搭建網路請求元件——監聽回撥及部分原始碼解析
Android 利用RxJava和Retrofit搭建網路請求元件——基礎配置及部分原始碼解析
基礎配置
一.定義網路請求方法的介面檔案:ApiService.class(名字隨意)
ApiService.class定義了各個請求方法,請求方式及引數型別均以註解形式標識,示例檔案僅描述了GET與POST請求方式
/**
* 注意:ApiService 必須是介面,且不能實現其他介面
* Created by cuiyan on 16-10-18.
*/
public interface ApiService {
/*************************GET 請求方式*************************/
/**
* ApiConstants.QQ_SPORT_API 請求介面地址api(相對路徑)
* 域名或ip部分會在構建Retrofit時設定
* 返回Observable物件(內部包裝了Call例項),訂閱(subscribe)執行時會呼叫Call.execute()方法傳送網路請求。
* 預設情況下,返回結果為retrofit2.Call物件,只有在構建Retrofit例項時設定了RxJava2CallAdapterFactory才支援請求方法返回Observable物件
*/
@GET(ApiConstants.QQ_SPORT_API)
Observable<NewsResult> getQQSportNews(@Query("baid") String baid, @Query("apikey") String apiKey);
@GET(ApiConstants.QQ_SPORT_API)
Observable<NewsResult> getQQSportNews1(@QueryMap Map<String, String> paramsMap);
/*************************POST 請求方式*************************/
/**
* @Body 註解引數均表示以實體形式提交請求資料
*/
@POST(ApiConstants.QQ_SPORT_API)
Observable<NewsResult> getQQSportNews2(@Body NewsResult bodyParam);
/**
* @Field 或 @FieldMap 註解引數均表示以表單形式提交引數,相應的,
* 請求方法必須新增 @FormUrlEncoded 註解
*/
@FormUrlEncoded
@POST(ApiConstants.QQ_SPORT_API)
Observable<NewsResult> getQQSportNews3(@Field("baid") String baid, @Field("apikey") String apiKey);
@FormUrlEncoded
@POST(ApiConstants.QQ_SPORT_API)
Observable<NewsResult> getQQSportNews4(@FieldMap Map<String, String> paramsMap);
}
二.ApiService例項構建及相關配置
public class BaseServiceUtil {
private static final int DEFAULT_TIMEOUT = 10;
/**
@param serviceClass 網路請求介面描述檔案類,步驟一中的ApiService.class或其他類似class
@return S S例項,即ApiService例項
*/
public static synchronized <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null);
}
public static <S> S createService(Class<S> serviceClass, String baseUrl) {
CommonInterceptor interceptor = new CommonInterceptor();
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create()) // 設定Converter.Factory(請求響應資料轉換器),我們設定的是GsonConverterFactory
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()); // 重點1:為Retrofit設定CallAdapter.Factory,這裡我們設定的是RxJava2CallAdapterFactory。ApiService 中網路請求方法預設返回retrofit2.Call物件,新增RxJava2CallAdapterFactory後支援返回Observable物件
// retrofitBuilder.callFactory()
// 一定要設定且必須格式正確的baseUrl
if (!TextUtils.isEmpty(baseUrl)) {
retrofitBuilder.baseUrl(baseUrl);
} else {
retrofitBuilder.baseUrl(BuildConfig.BASE_URL);
}
clientBuilder.interceptors().clear();
clientBuilder.interceptors().add(interceptor); // 重點2:為OkHttpClient(實現了okhttp3.Call.Factory介面)設定攔截器
// 設定https證照
// try {
// clientBuilder.sslSocketFactory(RqbTrustManager.getInstance().getSSLSocketFactory("BKS", R.raw.rqb_ssl));
// } catch (Exception e) {
// e.printStackTrace();
// }
OkHttpClient client = clientBuilder.build();
// 重點3:為Retrofit設定okhttp3.Call.Factory,OkHttpClient實現了okhttp3.Call.Factory介面,該方法內實際呼叫了
// callFactory(okhttp3.Call.Factory factory)方法為Retrofit設定okhttp3.Call.Factory。此行與下一行可合併,此處有意拆開做標註
retrofitBuilder.client(client);
// 重點4:構建Retrofit例項
Retrofit retrofit = retrofitBuilder.build();
// 重點5:構建ApiService例項
return retrofit.create(serviceClass);
}
}
三.網路請求訂閱者(觀察者)
/**
* 網路請求訂閱者
* Created by cuiyan on 16/6/2 14:09
*/
public class NetRequestSubscriber<T> implements Observer<T> {
private Dialog progressDialog;
private Disposable disposable;
private NetRequestCallback<T> netRequestCallback;
private Context context;
/**
* @param netRequestCallback 網路請求回撥
*/
public NetRequestSubscriber(@NonNull NetRequestCallback<T> netRequestCallback, Context context) {
this(netRequestCallback, context, false, null);
}
/**
* @param netRequestCallback 網路請求回撥
* @param showProgress 是否顯示網路請求載入對話方塊
* @param progressTip loading提示語
* @see NetProgressDialog
*/
public NetRequestSubscriber(@NonNull final NetRequestCallback<T> netRequestCallback, Context context, boolean showProgress, String progressTip) {
this.netRequestCallback = netRequestCallback;
this.context = context;
if (showProgress) {
progressDialog = NetProgressDialog.getInstance(context, progressTip, new OnNetProgressCancelListener() {
@Override
public void onCancelRequest() {
cancelRequest()
}
});
}
}
/**
* @param netRequestCallback 網路請求回撥
* @param progressDialog dialog 自定義對話方塊
*/
public NetRequestSubscriber(@NonNull NetRequestCallback<T> netRequestCallback, Context context, @NonNull Dialog progressDialog) {
this.netRequestCallback = netRequestCallback;
this.context = context;
this.progressDialog = progressDialog;
}
@Override
public void onSubscribe(@NonNull Disposable d) {
this.disposable = d;
showProgress();
onRequestStart();
}
@Override
public synchronized void onNext(final T t) {
if (t == null) {
onRequestResultNull();
} else {
if (t instanceof BaseResult && !Config.REQUEST_SUCCESS_CODE.equals(((BaseResult) t).getCode())) {
ToastUtil.showToast(context, ((BaseResult) t).getMessage());
}
onRequestSuccess(t);
}
}
@Override
public synchronized void onError(Throwable throwable) {
dismissProgress();
onRequestError(throwable);
if (throwable instanceof HttpException) {
ToastUtil.showToast(context, ((HttpException) throwable).message() + ((HttpException) throwable).code());
} else {
if (BuildConfig.DEBUG) {
ToastUtil.showToast(context, "error:" + throwable.getMessage());
} else {
ToastUtil.showToast(context, context.getString(R.string.error_net_request_failed));
}
}
}
/**
* {@link NetRequestSubscriber#onError(Throwable)}
* {@link Observer#onError(Throwable)}
* {@link Observer#onComplete()} (Throwable)}
* 該方法與onError方法互斥
*/
@Override
public void onComplete() {
dismissProgress();
netRequestCallback.onFinish();
}
private void onRequestStart() {
if (Looper.myLooper() != context.getMainLooper()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
netRequestCallback.onStart();
}
});
} else {
netRequestCallback.onStart();
}
}
private void onRequestSuccess(final T t) {
if (Looper.myLooper() != context.getMainLooper()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
netRequestCallback.onSuccess(t);
}
});
} else {
netRequestCallback.onSuccess(t);
}
}
private void onRequestResultNull() {
if (Looper.myLooper() != context.getMainLooper()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
netRequestCallback.onResultNull();
}
});
} else {
netRequestCallback.onResultNull();
}
}
private void onRequestError(final Throwable throwable) {
throwable.printStackTrace();
if (Looper.myLooper() != context.getMainLooper()) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
netRequestCallback.onError(throwable);
netRequestCallback.onFinish();
}
});
} else {
netRequestCallback.onError(throwable);
netRequestCallback.onFinish();
}
}
/**
*
*
*/
private void showProgress() {
if (progressDialog != null && !progressDialog.isShowing()) {
progressDialog.show();
}
}
private void dismissProgress() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
public void cancelRequest() {
dismissProgress();
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
netRequestCallback.onCancel();
netRequestCallback.onFinish();
}
}
四.網路請求控制器
public class BaseController {
/**
* @param subscriber 訂閱者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(final NetRequestSubscriber subscriber, Observable observable) {
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(subscriber);
}
/**
* @param activity 用於與observable繫結,activity生命週期結束時,自動取消訂閱
* @param observable 被觀察者
* @param subscriber 訂閱者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(RxActivity activity, final NetRequestSubscriber subscriber, Observable observable) {
observable.subscribeOn(Schedulers.io())
.compose(activity.bindToLifecycle()) //防止記憶體洩漏,activity生命週期結束後取消訂閱
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
/**
* @param fragment 用於與observable繫結,fragment生命週期結束時,自動取消訂閱
* @param subscriber 訂閱者
*/
@SuppressWarnings("unchecked")
public static synchronized void sendRequest(RxFragment fragment, final NetRequestSubscriber subscriber, Observable observable) {
observable.compose(fragment.bindToLifecycle()) //防止記憶體洩漏,fragment生命週期結束後取消訂閱
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
}
上述程式碼構建了完整網路請求功能,下面貼出應用示例。完整示例:https://github.com/670832188/TestApp
private void getNews() {
NetRequestSubscriber<NewsResult> subscriber = new NetRequestSubscriber<>(new NetRequestCallback<NewsResult>() {
@Override
public void onStart() {
setContentState(STATE_NET_PROGRESS);
}
@Override
public void onSuccess(@NonNull NewsResult newsResult) {
if (newsResult.getData() != null && newsResult.getData().size() > 0) {
setContentState(STATE_DATA_CONTENT);
newsAdapter.updateDataList(newsResult.getData());
} else {
setContentState(STATE_DATA_EMPTY);
}
}
@Override
public void onResultNull() {
setContentState(STATE_NET_ERROR);
}
@Override
public void onError(Throwable throwable) {
setContentState(STATE_NET_ERROR);
}
@Override
public void onCancel() {
super.onCancel();
}
@Override
public void onFinish() {
super.onFinish();
}
}, this);
Observable<NewsResult> observable = BaseServiceUtil.createService(ApiService.class, ApiConstants.JUHE_BASE_URL).getQQSportNews("69", Constant.JUHE_API_KEY);
BaseController.sendRequest(this, subscriber, observable);
}
流程梳理
上述程式碼中標註了五處重點:
1.Retrofit設定RxJava2CallAdapterFactory;
2.OkHttpClient(okhttp3.Call.Factory)設定Interceptor;
3.Retrofit設定OkHttpClient(okhttp3.Call.Factory);
4.構建Retrofit例項
5.構建ApiService例項
下面從Retrofit和ApiService例項構建為入口,分析基本流程及上述上述幾個配置是如何工作的
先看一下建立Retrofit例項的方法Retrofit.build()原始碼
1. public Retrofit build() {
2. if (baseUrl == null) {
3. throw new IllegalStateException("Base URL required.");
4. }
5. okhttp3.Call.Factory callFactory = this.callFactory;
6. if (callFactory == null) {
7. callFactory = new OkHttpClient();
8. }
9. Executor callbackExecutor = this.callbackExecutor;
10. if (callbackExecutor == null) {
11. callbackExecutor = platform.defaultCallbackExecutor();
12. }
13. // Make a defensive copy of the adapters and add the default Call adapter.
14. List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
15. adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
16. // Make a defensive copy of the converters.
17. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
18. return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,callbackExecutor, validateEagerly);
19. }
第1-第3行:首先檢測了之前設定的baseUrl,沒有設定的話直接丟擲異常。
第5-第8行:檢測是否設定了okhttp3.Call.Factory,沒有設定的話使用預設的OkHttpClient例項(前述程式碼中說過OkHttpClient實現了okhttp3.Call.Factory介面)。我們在程式碼中建立、配置了OkHttpClient例項(設定超時時間、攔截器),並設定於Retrofit例項。之所以沒有使用預設的OkHttpClient,是因為我們需要根據需求自定義超時時間、攔截器等
第14-15行:獲取CallAdapter.Factory列表,包括我們設定的RxJava2CallAdapterFactory和框架內建的預設CallAdapter.Factory,追蹤原始碼可以看到,內建的是ExecutorCallAdapterFactory.ExecutorCallbackCall。
注意:列表的順序,先新增的是我們設定的RxJava2CallAdapterFactory,請記住我們的RxJava2CallAdapterFactory是NO.1 NO.1 NO.1
第17行:獲取Converter.Factory列表,包括我們設定的GsonConverterFactory和內建的Converter.Factory(參見Rerofit.Builder構造方法)。
第18行:callFactory、adapterFactories 等作為構建引數傳入Retrofit構造方法建立Retrofit例項,看一下其構造方法:
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
成員變數callFactory 是我們設定的OkHttpClient;converterFactories包含了我們設定的GsonConverterFactory;adapterFactories 包含了我們設定的RxJava2CallAdapterFactory。暫且先有些印象,方便後續分析。
下面看ApiService例項構建方法Retrofit .create(final Class<T> service)原始碼:
1. public <T> T create(final Class<T> service) {
2. Utils.validateServiceInterface(service);
3. if (validateEagerly) {
4. eagerlyValidateMethods(service);
5. }
6. return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
7. new InvocationHandler() {
8. private final Platform platform = Platform.get();
9. @Override
10 public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
11. // If the method is a method from Object then defer to normal invocation.
12. if (method.getDeclaringClass() == Object.class) {
13. return method.invoke(this, args);
14. }
15. if (platform.isDefaultMethod(method)) {
16. return platform.invokeDefaultMethod(method, service, proxy, args);
17. }
18. ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
19. OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // 請留意okHttpCall
20. return serviceMethod.callAdapter.adapt(okHttpCall); // 請留心callAdapter
21. }
22. });
23. }
很直接、很暴力啊,利用Proxy建立的ApiService代理物件。檢視InvocationHandler的invoke方法,看看代理操作做了什麼處理。我們只關心我們的網路請求方法,我們的網路請求方法都是ApiService定義的,第12行判斷條件不滿足,pass;第15行判斷條件也不成立,具體原因可檢視platform的建立方法。
現在只剩下18-20行是我們需要關心的。先看第20行,我們的網路請求被萬惡的代理商劫持了,返回結果是serviceMethod.callAdapter.adapt(okHttpCall),如果你的記憶不是很差的話,應該記得我們的請求方法返回的Observable物件。是很明顯,我們需要知道這個callAdapter是什麼,瞭解它的adapt方法起到了什麼作用。定位到第18行,深入loadServiceMethod方法窺視一下
1. ServiceMethod<?, ?> loadServiceMethod(Method method) {
2. ServiceMethod<?, ?> result = serviceMethodCache.get(method);
3. if (result != null) return result;
4. synchronized (serviceMethodCache) {
5. result = serviceMethodCache.get(method);
6. if (result == null) {
7. result = new ServiceMethod.Builder<>(this, method).build();
8. serviceMethodCache.put(method, result);
9. }
10. }
11. return result;
12. }
很遺憾,這個方法沒有窺測到ServiceMethod是神馬角色。定位到上述程式碼第7行,繼續追擊ServiceMethod(ServiceMethod.class)
1. Builder(Retrofit retrofit, Method method) {
2. this.retrofit = retrofit;
3. this.method = method;
4. this.methodAnnotations = method.getAnnotations();
5. this.parameterTypes = method.getGenericParameterTypes();
6. this.parameterAnnotationsArray = method.getParameterAnnotations();
7. }
8. public ServiceMethod build() {
9. callAdapter = createCallAdapter();
10. responseType = callAdapter.responseType();
11. if (responseType == Response.class || responseType == okhttp3.Response.class) {
12. throw methodError("'"+ Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?");
13. }
14. responseConverter = createResponseConverter();
15. for (Annotation annotation : methodAnnotations) {
16 parseMethodAnnotation(annotation);
17. }
18. // 此處省略一萬個字...
19. return new ServiceMethod<>(this); // 此處要記住,後面有用
20. }
// 構造方法一併看了
21. ServiceMethod(Builder<R, T> builder) {
22. this.callFactory = builder.retrofit.callFactory(); // 此處請留意
23. this.callAdapter = builder.callAdapter;
24. this.baseUrl = builder.retrofit.baseUrl();
25. this.responseConverter = builder.responseConverter;
26. this.httpMethod = builder.httpMethod;
27. this.relativeUrl = builder.relativeUrl;
28. this.headers = builder.headers;
29. this.contentType = builder.contentType;
30. this.hasBody = builder.hasBody;
31. this.isFormEncoded = builder.isFormEncoded;
32. this.isMultipart = builder.isMultipart;
33. this.parameterHandlers = builder.parameterHandlers;
34. }
看Builder構造方法第2行,ServiceMethod持有我們之前建立的Retrofit例項。再看第9行callAdapter = createCallAdapter(); 我們要找的callAdapter(CallAdapter)終於浮出水面。我們之前說過,建立Retrofit例項的時候我們為其設定了CallAdapter.Factory,就是那個RxJava2CallAdapterFactory...(此處伏筆~~)。
從第9行繼續追蹤原始碼,最終定位到Retrofit的nextCallAdapter方法,此方法返回的CallAdapter就是我們要尋找的目標了
1. public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
2. checkNotNull(returnType, "returnType == null");
3. checkNotNull(annotations, "annotations == null");
4. int start = adapterFactories.indexOf(skipPast) + 1;
5. for (int i = start, count = adapterFactories.size(); i < count; i++) {
6. CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
7. if (adapter != null) {
8. return adapter;
9. }
10. }
11. // 此處省略一萬字(異常處理相關)
12. }
這段程式碼很就容易看懂了~。遍歷CallAdapter.Factory列表,通過Factory的get方法獲取匹配的CallAdapter,一猜就是通過我們設定的RxJava2CallAdapterFactory獲取的。為什麼這麼說呢?還記得之前我們說過,我們設定的RxJava2CallAdapterFactory是第一順位,狀元郎。看一下第4行,遍歷起點位置start值是多少?如果你自己追蹤到這塊程式碼,就會知道skipPast為null,所以start等於0,因此是從頭到尾遍歷列表,而我們的RxJava2CallAdapterFactory處於列表第一位。那就看一看RxJava2CallAdapterFactory部分原始碼吧
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
/**
* Returns an instance which creates synchronous observables that do not operate on any scheduler
* by default.
*/
public static RxJava2CallAdapterFactory create() {
return new RxJava2CallAdapterFactory(null, false);
}
private final @Nullable Scheduler scheduler;
private final boolean isAsync;
private RxJava2CallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
this.scheduler = scheduler;
this.isAsync = isAsync;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
if (rawType == Completable.class) {
// Completable is not parameterized (which is what the rest of this method deals with) so it
// can only be created with a single configuration.
return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
false, true);
}
boolean isFlowable = rawType == Flowable.class;
boolean isSingle = rawType == Single.class;
boolean isMaybe = rawType == Maybe.class;
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
boolean isResult = false;
boolean isBody = false;
Type responseType;
if (!(returnType instanceof ParameterizedType)) {
String name = isFlowable ? "Flowable"
: isSingle ? "Single"
: isMaybe ? "Maybe" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response<Foo> or Response<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
} else if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result<Foo> or Result<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
isResult = true;
} else {
responseType = observableType;
isBody = true;
}
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
}
上述原始碼做了刪減,只保留了我們關心的部分。我們在設定RxJava2CallAdapterFactory時,使用的是RxJava2CallAdapterFactory無參靜態方法create()建立的RxJava2CallAdapterFactory例項,顯然scheduler為null,isAsync為false。繼續看get方法,定位到return語句,返回的是RxJava2CallAdapter,構造RxJava2CallAdapter例項時傳入了一堆引數,我們關心一下scheduler、isAsync和isBody引數,不過多解析該方法,請自行深度查閱。scheduler為null,isAsync為false,isBody為true,以此為基礎繼續看RxJava2CallAdapter原始碼,程式碼不多,全部貼出
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
private final Type responseType;
private final @Nullable Scheduler scheduler;
private final boolean isAsync;
private final boolean isResult;
private final boolean isBody;
private final boolean isFlowable;
private final boolean isSingle;
private final boolean isMaybe;
private final boolean isCompletable;
// 構造方法
RxJava2CallAdapter(Type responseType, @Nullable Scheduler scheduler, boolean isAsync,
boolean isResult, boolean isBody, boolean isFlowable, boolean isSingle, boolean isMaybe,
boolean isCompletable) {
this.responseType = responseType;
this.scheduler = scheduler;
this.isAsync = isAsync;
this.isResult = isResult;
this.isBody = isBody;
this.isFlowable = isFlowable;
this.isSingle = isSingle;
this.isMaybe = isMaybe;
this.isCompletable = isCompletable;
}
@Override public Type responseType() {
return responseType;
}
@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物件
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;
}
}
直接看adapt方法第一行responseObservable,是一個Observable物件,該方法最終返回的也是Observable物件,且與responseObservable相關。先看看responseObservable吧,前述說過isAsync為false,所以responseObservable是CallExecuteObservable例項,感興趣您也可以看看CallEnqueueObservable原始碼(Android 利用RxJava和Retrofit搭建網路請求元件——監聽回撥及部分原始碼解析中有所提及)。之前還說過scheduler為null,isBody為true,綜合下來,最終return的是BodyObservable物件(對於其他情形可自行查閱相關程式碼),該BodyObservable例項的構造引數是responseObservable(CallExecuteObservable)。不管怎樣,BodyObservable確實是Observable,看來代理商並沒有做什麼壞事,真的與ApiService中我們期望的結果一樣。到此為止,我們已經知曉ApiService是如何返回Observable物件了,主動脈已經打通。不再分析BodyObservable原始碼,讀者可自行檢視,只是做了相關封裝處理,相對比較簡單。接下來繼續分析CallExecuteObservable原始碼
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
1. Call<T> call = originalCall.clone();
2. observer.onSubscribe(new CallDisposable(call));
3. boolean terminated = false;
4. try {
5. 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));
}
}
}
}
private static final class CallDisposable implements Disposable {
private final Call<?> call;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
call.cancel();
}
@Override public boolean isDisposed() {
return call.isCanceled();
}
}
先看一下我標記的第5行Response<T> response = call.execute();這行程式碼就是執行網路請求了,至於call例項的具體實現方式稍後分析,目前您只需要知道這麼多。
繼續分析該方法之前,我們先回憶一下,還記得訂閱者NetRequestSubscriber中有個cancelRequest()方法嗎,呼叫了onSubscribe(@NonNull Disposable d)方法中傳入的Disposable物件的dispose()方法來取消網路請求,為什麼這個方法能取消網路請求呢?回答這個問題要繼續看一下subscribeActual方法。看我標記的第2行observer.onSubscribe(new CallDisposable(call));CallDisposable是CallExecuteObservable定義的內部類,實現了Disposable介面,dispose()方法中呼叫了call.cancel()方法來取消網路請求,是不是與NetRequestSubscriber中的取消請求方法對上號了~。
到此為止,通過分析Retrofit例項、ApiService例項的構建及RxJava2CallAdapterFactory原始碼追蹤,我們已經知道了網路請求的執行、取消以及如何返回的Observable,之前提及的幾處重點已經粗略瞭解大半。但是我們還不知道攔截器如何被觸發工作的。下面繼續分析一下call例項是如何實現的,call.execute()方法到底做了什麼勾當,或許它與攔截器暗中勾結呢
回顧ApiService例項的構建方法,第18行
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // 請留意okHttpCall
上面提及的call例項就是這個okHttpCall啦。沒辦法,只能再看一看OkHttpCall原始碼了,做一下簡單瞭解,打入OkHttpCall內部,直接定位到execute()方法
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
// 註釋1:繼續追蹤createRawCall()方法吧...
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
// 此處請關聯上述註釋1
return parseResponse(call.execute());
}
看過原始碼很頭疼,顯然我們還要繼續追蹤createRawCall()方法,繼續吧
1. private okhttp3.Call createRawCall() throws IOException {
2. Request request = serviceMethod.toRequest(args);
// 此處想哭
3. okhttp3.Call call = serviceMethod.callFactory.newCall(request);
4. if (call == null) {
5. throw new NullPointerException("Call.Factory returned null.");
6. }
7. return call;
8. }
程式碼簡潔明瞭,繼續調查第3行吧,如果您的記憶不算差,應該記得之前我們為了尋找CallAdapter簡單分析過此serviceMethod的建立過程,現在它又回來了:我馬三立又回來了...
在ServiceMethod的構造方法中,可以知道callFactory其實是Retrofit例項的callFactory,而Retrofit例項的callFactory是我們設定的OkHttpClient例項,如果您已經沒有印象請返回檢視。好啦,直接看OkHttpClient的newwCall(Request request)方法,瞭解Call例項時如何建立的
@Override
public Call newCall(Request request) {
// 心中一萬個草泥馬,又牽涉到RealCall這個類
return new RealCall(this, request, false /* for web socket */);
}
哎,沒辦法,繼續檢視RealCall這個類吧,直接定位其execute()方法及相關聯方法
1. final class RealCall implements Call {
2. @Override
3. public Response execute() throws IOException {
4. synchronized (this) {
5. if (executed) throw new IllegalStateException("Already Executed");
6. executed = true;
7. }
8. captureCallStackTrace();
9. try {
10. client.dispatcher().executed(this);
11. Response result = getResponseWithInterceptorChain();
12. if (result == null) throw new IOException("Canceled");
13. return result;
14. } finally {
15. client.dispatcher().finished(this);
16. }
17. }
18. Response getResponseWithInterceptorChain() throws IOException {
19. // Build a full stack of interceptors.
20. List<Interceptor> interceptors = new ArrayList<>();
21. interceptors.addAll(client.interceptors()); // 我們設定的攔截器,處於列表第一位
// 以下幾個為內建攔截器
22. interceptors.add(retryAndFollowUpInterceptor);
23. interceptors.add(new BridgeInterceptor(client.cookieJar()));
24. interceptors.add(new CacheInterceptor(client.internalCache()));
25. interceptors.add(new ConnectInterceptor(client));
26. if (!forWebSocket) {
27. interceptors.addAll(client.networkInterceptors());
28. }
29. interceptors.add(new CallServerInterceptor(forWebSocket));
// 注意此處傳入的index引數為0,攔截器列表也被傳入RealInterceptorChain構造方法
30. Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);
31. return chain.proceed(originalRequest);
32. }
33. }
看一下第11行程式碼,執行這行程式碼獲取網路請求響應資料,但是仍然看不出攔截器是如何起作用的,但是請注意註釋部分,追擊getResponseWithInterceptorChain()方法試試。看第31行程式碼:執行chain.proceed(originalRequest)獲取的響應資料,硬著頭皮看看chain是什麼鬼。定位到第30行,查閱一下RealInterceptorChain構造方法及proceed方法
1. public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection, int index, Request request) {
2. this.interceptors = interceptors;
3. this.connection = connection;
4. this.streamAllocation = streamAllocation;
5. this.httpCodec = httpCodec;
6. // 上一步傳入此處的index為0
7. this.index = index;
8. this.request = request;
9. }
10. public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
11. if (index >= interceptors.size()) throw new AssertionError();
12. calls++;
13. // If we already have a stream, confirm that the incoming request will use it.
14. if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
15. throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
16. }
17. // If we already have a stream, confirm that this is the only call to chain.proceed().
18. if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
19 }
20. // Call the next interceptor in the chain.
21. RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 上一步傳入的index 為0,因此取我們設定的攔截器
22. Interceptor interceptor = interceptors.get(index);
23. Response response = interceptor.intercept(next);
24. // Confirm that the next interceptor made its required call to chain.proceed().
25. if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
26. }
27. // Confirm that the intercepted response isn't null.
28. if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
29. }
30. return response;
31. }
定位到第22行,終於看到了攔截器,取index為0,所以取第一個,就是我們設定的攔截器了;再看第23行,執行interceptor.intercept(next)攔截請求。攔截器觸發流程解析就此終結,至於攔截器的用法請參考Retrofit Interceptor(攔截器) 攔截請求並做相關處理
到此為止,我們已經梳理了網路請求大致流程,我們做的配置也做了解析,本文也到此結束
相關文章
- OKHttp網路請求原理流程解析HTTP
- MVVM框架的搭建(三)——網路請求MVVM框架
- 輕鬆搞定Retrofit不同網路請求方式的請求引數配置,及常用註解使用
- Android網路請求(4) 網路請求框架VolleyAndroid框架
- Android網路請求(終) 網路請求框架RetrofitAndroid框架
- Android網路請求(3) 網路請求框架OkHttpAndroid框架HTTP
- 淺析okHttp3的網路請求流程HTTP
- Retrofit網路請求原始碼解析原始碼
- 小程式系列之網路請求
- 小程式-網路請求封裝封裝
- 前端CORS請求梳理前端CORS
- js 幾種網路請求方式梳理——擺脫回撥地獄JS
- Retrofit原始碼解析之網路請求原始碼
- Volley 原始碼解析之網路請求原始碼
- 原始碼分析Retrofit請求流程原始碼
- axios原始碼分析——請求流程iOS原始碼
- SpringMVC請求流程原始碼分析SpringMVC原始碼
- 網路請求了
- 網路請求優化之取消請求優化
- Axios 請求配置引數詳解以及全域性配置示例iOS
- Axios 原始碼解讀 —— 網路請求篇iOS原始碼
- OkHttp 原始碼分析(一)—— 請求流程HTTP原始碼
- HTTP網路請求原理HTTP
- 網路資料請求
- Android網路請求(2)Android
- flutter之從零開始搭建(三)之 網路請求Flutter
- 請求基本流程
- 72 頁 PPT,帶你梳理神經網路完整架構(含 PyTorch 實現程式碼片段)神經網路架構PyTorch
- Mac搭建appium環境及python執行程式碼示例MacAPPPython行程
- webpack構建流程及梳理Web
- 傳送GET請求 示例
- OC:封裝網路請求封裝
- iOS 使用Moya網路請求iOS
- Jest中Mock網路請求Mock
- ThinkPHP6 原始碼分析之請求流程PHP原始碼
- 輕鬆搞定Retrofit不同網路請求方式的請求引數配置,Retrofit常用註解的使用
- 網路搭建的基本流程包括
- Redis(一):服務啟動及基礎請求處理流程原始碼解析Redis原始碼