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

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

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


时间: 2024-10-21 00:37:29

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

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

面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本.这个框架里的组件是配合 Android 组件生命周期的,所以它能够很好的规避组件生命周期管理的问题.今天我们就来看看这个库的使用. 通用的框架准则 官方建议在架构 App 的时候遵循以下两个准则: 关注分离 其中早期开发 App 最常见的做法是在 Activity 或者 Fragment 中写了大量

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

什么是 Repository 模式 Repository 这个词直译过来仓库.仓储的意思.这个意思其实也能反应出 Repository 模式作用.App 开发中少不了对数据的操作,数据的来源可能有很多种:网络.数据库.文件以及内存中的缓存.而 Repository 就相当于一个仓库管理员,管理这些数据的存储.当业务层想要获取或者存储数据时,只需要通过 Repository 的管理员进行操作.这样的好处就是:屏蔽数据来源的操作接口.对于业务层来说不必关心数据存在哪里,以及如何存储的.而且也符合我们

Anroid-async-http封装网络请求框架源码分析

Android-async-http开源项目可以是我们轻松的获取网络数据或者向服务器发送数据,使用起来非常简单, 这个网络请求库是基于Apache HttpClient库之上的一个异步网络请求处理库,网络处理均基于Android的非UI线程,通过回调方法处理请求结果. 主要特点:处理异步Http请求,并通过匿名内部类处理回调结果,Http异步请求均位于非UI线程,不会阻塞UI操作,通过线程池处理并发请求处理文件上传.下载,响应结果自动打包JSON格式. 一, Android-async-http

基于AFNetWorking搭建APP的网络请求框架[iOS]

自从AFNetWorking(下文简称AFN)更新2.0版本之后,AFN的许多的问题得到的有效的解决,写法也得到了完善.前期主流的第三方网络类库 ASI作者宣布不再维护,国内大多数的主流APP都逐步接受并开始采用AFN.出于各自公司项目的不同需要,大家都会在AFN的基础上加一层不尽相同的封 装.很多新APP在选择方式时也会非常纠结.如何封装才可以让AFN更有效率更方便的应用于项目呢,对于这个问题,各人有各人的看法.基于做过以及读过的 几个项目,也来谈一下如何搭建一个APP的网络请求框架.由于本人

iOS开发项目篇—35封装网络请求

iOS开发项目篇—35封装网络请求 一.简单说明 1.分析项目对网路请求(AFN框架)的依赖 项目中,多个控制器都使用了AFN框架发送网络请求,如果AFN2.0存在重大BUg,或者是升级至3.0版本,那么对于整个项目都是及其危险的,所有用到AFN的地方都需要做出相应的修改. 另外,如果现在要求不再使用AFN框架,而是使用一个新的框架,那么有关AFN的依赖所关联的所有代码都需要重新来过. 如果把afn这个第三方框架从项目中删除的话,那么项目就相当于作废了,这就是项目对第三方框架的强依赖的体现. 说

[iOS微博项目 - 3.3] - 封装网络请求

github: https://github.com/hellovoidworld/HVWWeibo A.封装网络请求 1.需求 为了避免代码冗余和对于AFN框架的多处使用导致耦合性太强,所以把网络请求封装成自己的工具类,以后便于更换网络框架. 2.思路 创建一个自定义工具类,提供类方法来实现网络请求 3.实现 1 // 2 // HVWNetworkTool.h 3 // HVWWeibo 4 // 5 // Created by hellovoidworld on 15/2/9. 6 //

封装网络请求

封装网络请求类便捷, 适合多个地方使用. 第一封装下载方法 前提用Cocoapods或者直接引用第三方AFNetWorking 定义一个类NetWorkingManager, 继承于NSObject A: 在.h中写方法声明 #import <Foundation/Foundation.h> @interface NetWorkManager : NSObject - (void)downLoadWithUrl:(NSString *)url progress:(void(^)(float p

四种网络请求的方式封装网络请求

封装网络请求类便捷, 适合多个地方使用. 第一封装下载方法 前提用Cocoapods或者直接引用第三方AFNetWorking 定义一个类NetWorkingManager, 继承于NSObject A: 在.h中写方法声明 #import <Foundation/Foundation.h> @interface NetWorkManager : NSObject - (void)downLoadWithUrl:(NSString *)url progress:(void(^)(float p

ios中封装网络请求类

ios中封装网络请求类 #import "JSNetWork.h" //asiHttpRequest #import "ASIFormDataRequest.h" //xml 的解析 #import "UseXmlParser.h" //判断是否联网 #import "Reachability.h" //sbJson,判断json的解析 #import "JSON.h" @implementation JS