RxJava+Retrofit2搭建網路請求元件完整配置、示例程式碼及流程梳理

weixin_33936401發表於2018-04-27

本文是對之前寫的兩篇文章的綜合概述及全流程梳理
Android 利用RxJava和Retrofit搭建網路請求元件——監聽回撥及部分原始碼解析
Android 利用RxJava和Retrofit搭建網路請求元件——基礎配置及部分原始碼解析

11451103-cecaa6b74221bd89.gif

基礎配置

一.定義網路請求方法的介面檔案: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(攔截器) 攔截請求並做相關處理

到此為止,我們已經梳理了網路請求大致流程,我們做的配置也做了解析,本文也到此結束


11451103-9a6014439e1bff00.png

相關文章