在 App 開發中網絡請求是每一個開發者必備的開發庫,也出現了許多優秀開源的網絡請求庫。例如html
這些網絡請求庫很大程度上提升程序猿的編碼效率。可是隨着業務的發展,App 變得愈來愈大,咱們將這些網絡請求庫加入到項目中直接使用,對咱們業務類的入侵是很是強的。若是要進行業務分離時,這些網絡請求代碼將是一個阻止咱們進一步工做的絆腳石。對開發者來講是很是痛苦的。java
所以咱們構建的網絡請求框架要能夠解決如下問題:android
因此在 App 組件化/模塊化開發架構思路 一文中,咱們把網絡請求做爲內核層的一個組件。git
通常來講,目前絕大部分 App 的數據請求都是使用 HTTP 協議,而數據交換的協議使用 json 格式。所以能夠封裝一個通用的請求接口。(固然還有其餘一些協議,例如微信的 mars ,可是封裝的思路是一致的,本文爲了簡單說明,暫時使用通用網絡請求框架,不排除之後會對 mars 的封裝)github
首先預覽一下框架結構json
這個類封裝了網絡請求的通用接口,定義請求接口 doRequest()
、獲取請求鏈接 getUrl()
、獲取請求方法 getHttpMethod()
等。微信
public interface IRequest { enum HttpMethod { GET, POST, PUT, DELETE } //... 爲了減小代碼的篇幅,省略一些對本文說明不重要的片斷,本文代碼能夠在 //https://github.com/wecodexyz/Componentization 獲取到 void addParams(Map<String, String> params); String getUrl(); Pair<Integer, String> doRequest(); boolean isSupportCache(); void addHeader(String key, String value); HttpMethod getHttpMethod(); //... 爲了減小代碼的篇幅,省略一些對本文說明不重要的片斷,本文代碼能夠在 //https://github.com/wecodexyz/Componentization 獲取到 }
這個類是個抽象類,對 IRequest
的實現。目前是一個簡單封裝的實現。網絡
這個類是一個泛型類,繼承於 Request
並對第三方請求庫的封裝。例如本文就是對 okhttp
的封裝,而泛型 T 對象就是請求獲得的具體數據類型。若是要對其餘請求庫進行封裝,就能夠參考這個類的實現。架構
注意這個類封裝是純粹的網絡請求,不該該包含業務類相關的代碼。不然無解決上文提出的三個問題。app
public abstract class RequestWrapper extends Request { //... 爲了減小代碼的篇幅,省略一些對本文說明不重要的片斷,本文代碼能夠在 //https://github.com/wecodexyz/Componentization 獲取到 @Override public Pair<Integer, String> doRequest() { Pair<Integer, String> result = new Pair<>(ERROR_NETWORK, ""); okhttp3.Request request = null; if (getHttpMethod() == HttpMethod.POST) { request = requestBuilder().url(getUrl()).post(requestBody()).build(); } else { request = requestBuilder().url(getUrlWithParams()).build(); } try { Response response = mClient.newCall(request).execute(); if (response.isSuccessful()) { result = new Pair<>(response.code(), response.body().string()); } else { result = new Pair<>(response.code(), response.message()); } } catch (IOException e) { Log.e(TAG, e.getMessage()); } return result; } //... 爲了減小代碼的篇幅,省略一些對本文說明不重要的片斷,本文代碼能夠在 //https://github.com/wecodexyz/Componentization 獲取到 }
關鍵的代碼是在 doRequest()
方法中,該方法實現了網絡請求的代碼,返回一個 Pair<Integer,String>
對象,該對象的 first
屬性是一個請求 code
,用於標識網絡請求碼(便是網絡請求返回的200,404,301等)。而 second
就是網絡請求的數據。
這個類就是網絡請求框架提供給業務類使用的一個接口。本文一開始就提出來 json 做爲交互數據請求的協議。那麼此類的封裝就有利於業務數據的訪問。
public abstract class BaseTextRequest<T> extends RequestWrapper { public BaseTextRequest(Context context) { super(context); } public Flowable<T> request() { return Flowable.fromCallable(new Callable<Pair<Integer, String>>() { @Override public Pair<Integer, String> call() throws Exception { Pair<Integer, String> result = doRequest(); return result; } }).flatMap(new Function<Pair<Integer, String>, Publisher<T>>() { @Override public Publisher<T> apply(@NonNull Pair<Integer, String> pair) throws Exception { if (isSuccessful(pair.first)) { return Flowable.just(onRequestFinish(pair.second)); } return Flowable.just(onRequestError(pair.first, pair.second)); } }); } @Override public boolean isSupportCache() { return true; } protected abstract T onRequestFinish(String result); protected abstract T onRequestError(int code, String message); }
因爲請求網絡是耗時的操做,rxjava2 來實現網絡請求異步操做。 request
是對 RequestWrapper.doRequest() 方法的封裝,並獲得一個 Flowable
對象。同時定義了 onRequestFinish()
和 onRequestError()
兩個方法。
這兩個方法就是具體業務類要處理的邏輯。
假設有一個請求業務數據接口,返回數據是一個字符串。那麼咱們使用咱們的框架就是這樣來使用。本文例子是請求咱們項目中的 README.md 的內容。用起來很是簡單,只要繼承於 BaseTextRequest,並實現 getUrl()
、 onRequestFinish()
onRequestError()
、 getHttpMethod()
這幾個方法。
注意嚴格來講這是一個業務類,因此是不該該放在 core 目錄下的。
public class SimpleTextRequest extends BaseTextRequest<String> { public SimpleTextRequest(Context context, Map<String, String> params) { super(context); addParams(params); } @Override public String getUrl() { return "https://raw.githubusercontent.com/wecodexyz/Componentization/master/README.md"; } @Override public HttpMethod getHttpMethod() { return HttpMethod.GET; } @Override protected String onRequestFinish(String result) { //這裏能夠實現對 json 數據的解析,例如使用 JSONObject //對象解析具體的業務 return result; } @Override protected String onRequestError(int code, String message) { return message; } }
request = new SimpleTextRequest(this, null); request.request() .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<String>() { @Override public void accept(@NonNull String s) throws Exception { textView.setText(s); //這裏返回接口請求的數據 } }, new Consumer<Throwable>() { @Override public void accept(@NonNull Throwable throwable) throws Exception { textView.setText(throwable.getMessage()); } });
本文運行的結果
項目地址:https://github.com/wecodexyz/Componentization
微信關注咱們,能夠獲取更多