1. 程式人生 > >RxJava練武場之——基於RxJava Retrofit網路框架的搭建

RxJava練武場之——基於RxJava Retrofit網路框架的搭建

RxJava練武場是一個rxjava在專案中應用的小系列,包括:

Observable網路框架的抽象

Observable網路框架建立的原因

兩個問題:

  • Retrofit已經對網路請求做了封裝,為什麼還要封裝?

    網路請求中對於請求流程、配置、加解密、異常處理每個app都是固定不變的,如果業務每次請求都自己處理,會存在冗餘程式碼,且質量不易保證。所以我們需要基於Retrofit對這些流程和操作做二次封裝,並對呼叫方式進行統一,我們稱之為網路框架。

  • 框架封裝方式Observable是什麼?

    網路框架,傳統使用callback/listener方式非同步回撥網路請求結果。但是這種callback的方式,沒有利用到Retrofit的一大優勢--rxjava呼叫,所以我們要基於rxjava呼叫方式,封裝一個基於Observable的網路請求框架。 以下所說網路框架,均指基於Observable的網路請求二次封裝框架。

Observable網路框架設計目標

  1. T1:支援Get、Post請求,對Request的業務params、url可輕鬆配置
  2. T2:對Request中params組合和加密,統一處理
  3. T3:返回Response 解密處理,並自動JavaBean化
  4. T4:返回Response code/status 判斷及統一處理
  5. T5:網路請求cancle機制、progressBar等通用處理

Observable網路框架如何實現

設計原則:

  1. 網路框架Api返回Observable物件,並作為網路請求事件的生產者: 生產者負責請求的發起,和返回資料的處理。

  2. 業務註冊Observer類,作為消費者。

    只負責對返回資料的響應

生產者和消費者界限明確,做到完全解耦,為網路請求與其他rxjava非同步呼叫的整合打基礎。


這篇文章詳細講述框架中生產者的實現,消費者的實現在《基於Rxjava Retrofit的網路框架(二)》中介紹

在Observable的建立過程中,框架如何封裝?

首先我們需要一個Manager或Helper全域性控制代碼,通過他可以發起網路請求,一般設計為單例全域性持有,有利於網路請求一些資源的共用。 我們暫定為NetHelper,其網路請求介面定義為:

private static <R extends HttpResponse<?>> Observable sendRequest(final ObservableRequest<R> orgRequest) 
複製程式碼

sendRequest方法中,我們來看下Observable物件的生成過程:參考Retrofit本身Observable生成方式

第一步

定義Request,Request類的定義在Retrofit裡通過註解的方式完成的

public interface Request {

    @POST("{url}")
    Observable<JSONObject> postJSONResult(@Path(value="url",encoded =true) String url, @FieldMap Map<String, String> params);
}

複製程式碼

原來Retrofit中每個請求都要為request定義一個interface,並且返回的response型別需要此處指明,那除此之外請求的入參要在另一個地方單獨定義。

我們定義的Observable泛型是通用的JSONObject,這樣做的好處是每個Request子類,只需要一個類宣告自己入參和url,無需單獨定義interface宣告response型別。

第二步

建立retrofit;

NetHelper.java中

// 初始化okhttp
OkHttpClient client = new OkHttpClient.Builder()
        .build();
/**
 *OkHttpClient每次請求的時候都要建立,注意:OkHttpClient.Builder()中有ConnectionPool作為OkHttp的   	*連線池要複用,否則請求過多時容易導致記憶體溢位
**/

// 初始化Retrofit
retrofit = new Retrofit.Builder()
        .client(client)
        .baseUrl(Request.HOST)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(MyConverterFactory.create())
        .build();

複製程式碼

一般addConverterFactory配置是GsonConverterFactory,用於把Response通過GSon轉為javaBean(Request介面中定義的型別),由於我們定義為了JsonObject,所以我們使用MyConverterFactory自定義實現

第三步

生成Observable

Observable的真正建立,我們放到Request基類中

public abstract class HttpRequest<T extends HttpResponse>{
    protected abstract String getURLAction();
    
    //Observable的建立
    public Observable getObservable(Retrofit retrofit) {
        Request request = retrofit.create(Request.class);
		return request.postJSONResult(getURLAction(),getURLParam());
    }
    
    public String getBaseURL(){
        //return base url;
    }
    
    public SortedMap<String, String> getURLParam() {
    	//return 對HttpRequest子類(業務類),定義的params,進行組合和加密
    	//通用的組合和加密邏輯就在此處。
    }
    
    //response型別解析
    protected Type type;

    public ObservableMapiRequest(BaseContext context) {
        super(context);
        initType();
    }

    private void initType() {
        Type superClass = getClass().getGenericSuperclass();

        this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];

    }

    public Type getType() {
        return type;
    }
}
複製程式碼

以上三步,已經初步將Observable返回。通過以上幾步只是基於Retrofit自身的Observable建立方法做了一些封裝。下面的處理是框架的重點和核心:

private static <R extends HttpResponse<?>> Observable sendRequest(final ObservableRequest<R> orgRequest){
        return NetHelper.getApiObservable(orgRequest)
                .map(new JavaBeanFunc(orgRequest.getType()))
                .filter(new LogInterceptor(orgRequest))
                .compose(ResponseTransformer.handleResult())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

    }
複製程式碼

NetHelper.getApiObservable方法後,再加上網路請求的執行緒配置,這時候業務subscribe消費者,就可以直接得到解密後的JsonObject了。注意此時只是JSONObject,我們需要轉換成我們需要的Response。

我們在HttpRequest類中看到了,定義HttpRequest子類時,是需要傳入Response型別的(就是T),在HttpRequest類中已經將Response的型別解析出來,並儲存了。

public class JavaBeanFunc<J extends JSONObject,T extends HttpResponse> implements Function<J,T> {
    Type mCon;
    public JavaBeanFunc(Type con){
        mCon = con;
    }
    @Override
    public T apply(J jsonObject) throws Exception {
        if (jsonObject != null){
            T response = jsonObject.toJavaObject(mCon);
            return response;
        } else {
            return null;
        }
    }
}
複製程式碼

同時配置了攔截器,用於log輸出,和異常的攔截,也可以做網路效能指標的記錄等

public class LogInterceptor<R extends HttpResponse<?>> implements Predicate<R> {
    private HttpRequest<R> orgRequest;

    public LogInterceptor(HttpRequest<R> request){
        orgRequest = request;
    }

    @Override
    public boolean test(R response) throws Exception {
        boolean isPredicate = false;
        if (orgRequest != null && response != null) {
            HttpHelper.printHttpLog(orgRequest, JSONObject.toJSONString(response));
            isPredicate = true;
        }
        return isPredicate;
    }
}
複製程式碼

response解析完畢之後,還沒有完事;必須對response的正常和異常兩種情況做一個判斷,哪些情況作為onNext傳遞,哪些情況作為onError傳遞,也要定義清楚。

有些文章對於progressbar的控制也放到這裡,我認為並不符合框架的設計原則,不屬於生產者該做的事情。

public static <T extends Serializable> ObservableTransformer<T, T> handleResult() {
    return upstream -> upstream
            .onErrorResumeNext(new ErrorResumeFunction<T>())
            .flatMap(new ResponseFunction<T>());
}

private static class ErrorResumeFunction<T extends Serializable> implements Function<Throwable, ObservableSource<? extends T>> {

    @Override
    public ObservableSource<? extends T> apply(Throwable throwable) throws Exception {
        return Observable.error(CustomException.handleException(throwable));
    }
}

private static class ResponseFunction<T extends Serializable> implements Function<T, ObservableSource<T>> {

    @Override
    public ObservableSource<T> apply(T tResponse) throws Exception {
        int code = tResponse.getCode();
        String message = tResponse.getMsg();

        if (code == SUCCESS.value()) {
            return Observable.just(tResponse);
        } else {
            return Observable.error(new ApiException(code, message));
        }
    }
}
複製程式碼

你可能有兩個疑問,一個是response中code的判定可以在observer中處理嗎,另一個是伺服器錯誤和業務錯誤為何都作為error丟擲。

第一個問題: code值的判定不可以在observer中處理,而必須在Observable一端處理。因為Observable形式的網路請求是作為資料流中的一環出現的,可能當前網路請求只是一連串非同步呼叫(rxjava呼叫)的一環。 第二個問題: response中code!=SUCCESS是業務錯誤的情況,必須向資料流中發出,讓業務處理此異常。(那同時對於Response的定義也是,code!=SUCCESS必須是不需要業務處理的情況才行) 兩種錯誤都丟擲error(內部code不同),方便架構使用者在事件響應時,既能捕捉所有錯誤,又能區分錯誤的型別。