在 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
微信关注咱们,能够获取更多