App 组件化/模块化之路——如何封装网络请求框架

案头见蠹鱼,犹胜凡俦侣。这篇文章主要讲述App 组件化/模块化之路——如何封装网络请求框架相关的知识,希望能为你提供帮助。
在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库App 组件化/模块化之路——如何封装网络请求框架
在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库。例如

  • okhttp
  • retrofit
  • android-async-http
这些网络请求库很大程度上提高程序猿的编码效率。但是随着业务的发展,App 变得越来越大,我们将这些网络请求库加入到项目中直接使用,对我们业务类的入侵是非常强的。如果要进行业务分离时,这些网络请求代码将是一个阻止我们进一步工作的绊脚石。对开发者来说是非常痛苦的。
因此我们构建的网络请求框架要可以解决以下问题:
  • 分离业务与网络请求代码
  • 网络库可以很容易的被替换
  • 网络库可以很方便的复用
所以在 App 组件化/模块化开发架构思路 一文中,我们把网络请求作为内核层的一个组件。
封装第三方网络请求接口一般来说,目前绝大部分 App 的数据请求都是使用 HTTP 协议,而数据交换的协议使用 json 格式。因此可以封装一个通用的请求接口。(当然还有其他一些协议,例如微信的 mars ,但是封装的思路是一致的,本文为了简单说明,暂时使用通用网络请求框架,不排除以后会对 mars 的封装)
首先预览一下框架结构
App 组件化/模块化之路——如何封装网络请求框架

文章图片

IRequest这个类封装了网络请求的通用接口,定义请求接口 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 获取到 }

 
Request这个类是个抽象类,对 IRequest 的实现。目前是一个简单封装的实现。
RequestWrapper这个类是一个泛型类,继承于 Request 并对第三方请求库的封装。例如本文就是对 okhttp 的封装,而泛型 T 对象就是请求得到的具体数据类型。如果要对其他请求库进行封装,就可以参考这个类的实现。
注意这个类封装是纯粹的网络请求,不应该包含业务类相关的代码。否则无解决上文提出的三个问题。
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 就是网络请求的数据。
BaseTextRequest这个类就是网络请求框架提供给业务类使用的一个接口。本文一开始就提出来 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() 两个方法。
这两个方法就是具体业务类要处理的逻辑。
SimpleTextRequest假设有一个请求业务数据接口,返回数据是一个字符串。那么我们使用我们的框架就是这样来使用。本文例子是请求我们项目中的 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()); } });

 
本文运行的结果
App 组件化/模块化之路——如何封装网络请求框架

文章图片

 
项目地址:https://github.com/wecodexyz/Componentization
微信关注我们,可以获取更多

【App 组件化/模块化之路——如何封装网络请求框架】
App 组件化/模块化之路——如何封装网络请求框架

文章图片


    推荐阅读