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

在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库。例如

这些网络请求库很大程度上提高程序猿的编码效率。但是随着业务的发展,App 变得越来越大,我们将这些网络请求库加入到项目中直接使用,对我们业务类的入侵是非常强的。如果要进行业务分离时,这些网络请求代码将是一个阻止我们进一步工作的绊脚石。对开发者来说是非常痛苦的。

因此我们构建的网络请求框架要可以解决以下问题:

  • 分离业务与网络请求代码
  • 网络库可以很容易的被替换
  • 网络库可以很方便的复用

所以在 App 组件化/模块化开发架构思路 一文中,我们把网络请求作为内核层的一个组件。

封装第三方网络请求接口

一般来说,目前绝大部分 App 的数据请求都是使用 HTTP 协议,而数据交换的协议使用 json 格式。因此可以封装一个通用的请求接口。(当然还有其他一些协议,例如微信的 mars ,但是封装的思路是一致的,本文为了简单说明,暂时使用通用网络请求框架,不排除以后会对 mars 的封装)

首先预览一下框架结构

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());
}
});

本文运行的结果

项目地址:https://github.com/wecodexyz/Componentization

微信关注我们,可以获取更多

App 组件化/模块化之路——如何封装网络请求框架的更多相关文章

  1. App 组件化/模块化之路——使用SDK的思路进行模块化设计接口

    在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...

  2. App 组件化/模块化之路——Android 框架组件(Android Architecture Components)使用指南

    面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本. ...

  3. App 组件化/模块化之路——构建开发架构思路

    App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...

  4. App 组件化/模块化之路——Repository 模式

    什么是 Repository 模式 Repository 这个词直译过来仓库.仓储的意思.这个意思其实也能反应出 Repository 模式作用.App 开发中少不了对数据的操作,数据的来源可能有很多 ...

  5. Android 组件化/模块化之路——在展示层搭建MVP结构

    Android 组件化/模块化之路——在展示层搭建MVP结构 什么是MVP Model–View–Presenter (MVP) 源于 Model–View–Controller (MVC) 的结构设 ...

  6. 第六十二篇、AFN3.0封装网络请求框架,支持缓存

    1.网络请求 第一种实现方式: 功能:GET POST 请求 缓存逻辑: 1.是否要刷新本地缓存,不需要就直接发起无缓存的网络请求,否则直接读取本地数据 2.需要刷新本地缓存,先读取本地数据,有就返回 ...

  7. 得到、微信、美团、爱奇艺APP组件化架构实践

    一.背景 随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多.此过程中,你是否有过以下烦恼? 项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能忍? 改了一行代码 或只调 ...

  8. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  9. 2020,最新APP重构:网络请求框架

    在现在的app,网络请求是一个很重要的部分,app中很多部分都有或多或少的网络请求,所以在一个项目重构时,我会选择网络请求框架作为我重构的起点.在这篇文章中我所提出的架构,并不是所谓的 最好 的网络请 ...

随机推荐

  1. Swift 入门之简单语法(六)

    KVC 字典转模型构造函数 /// `重写`构造函数 /// /// - parameter dict: 字典 /// /// - returns: Person 对象 init(dict: [Str ...

  2. Autotest添加测试用例小结

    Autotest本身是一个自动化测试框架,可以在上面添加各种测试工具用于系统测试.前几天我在上面添加了几个基于龙芯桌面5.0系统的性能测试工具.现在做以下总结,大体写以下添加的过程. 以unixben ...

  3. 用java实现简单快速的webservice客户端/数据采集器(支持soap1.1和soap1.2标准,支持utf-8编码)

    前言: 用了cxf,axis等各种wbeservice实现库,简单试用了一下动态调用的方式,很不满意,完全无法满足业务的需要,所以自己实现了一个webservice采集客户端,方便动态调用外部webs ...

  4. JQuery与js具体使用的区别(不全,初学)

    jQuery能大大简化Javascript程序的编写 要使用jQuery,首先要在HTML代码最前面加上对jQuery库的引用,比如: <script language="javasc ...

  5. Github 开源:高效好用的对象间属性拷贝工具:升讯威 Mapper( Sheng.Mapper)

    Github 地址:https://github.com/iccb1013/Sheng.Mapper 对象属性值映射/拷贝工具.不需要创建映射规则,不要求对象类型一致,适用于简单直接的拷贝操作,可以全 ...

  6. 快速排序(Quicksort)的Javascript实现

    日本程序员norahiko,写了一个排序算法的动画演示,非常有趣. 这个周末,我就用它当做教材,好好学习了一下各种排序算法. 排序算法(Sorting algorithm)是计算机科学最古老.最基本的 ...

  7. WPF MVVM 架构 Step By Step(4)(添加bindings - 完全去掉后台代码)

    之前的改进已经挺棒的,但是我们现在知道了后台代码的问题,那是否可能把后台代码全部去除呢?这时候就该WPF binding 和 commands 来做的事情了. WPF就是以超吊的binding,com ...

  8. maven项目转成web项目没有生成WebContent目录

    有时候建立maven项目转成web项目没有生成WebContent目录,此时把Dynamic web module 去掉勾选,然后ok,再点开项目的properties,再选中Dynamic web  ...

  9. [HNOI2009]梦幻布丁 算法技巧之邻接链

    题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...

  10. jenkins跑maven项目的时候报错,看评论

    Started by user admin Building in workspace /var/jenkins_home/workspace/helloworld [WS-CLEANUP] Dele ...