前言

Android真响应式架构系列文章:

Android真响应式架构——MvRx
Epoxy——RecyclerView的绝佳助手
Android真响应式架构——Model层设计
Android真响应式架构——数据流动性
Android真响应式架构——Epoxy的使用
Android真响应式架构——MvRx和Epoxy的结合

上篇文章介绍了Model层的设计,其本质是数据流的设计,即以RxJava的方式包装Model层的数据,然后进行合理的数据分层,以实现对数据流的分层管控。但是,对于最常用的网络数据而言(基于HTTP的网络请求),它只是单一的数据流,也就是说,一次网络请求只返回一组数据,然后数据流就切断了(onComplete被调用),如果数据发生了变化,需要再次发送网络请求。因此,有人建议应该使用Single来表示网络请求:

/** * Retrofit接口 */interface UserApi {    /**     * 获取用户信息     * 使用 Observable表示网络数据流     */    @GET    fun getUserInfo(): Observable        /**     * 获取用户信息     * 使用 Single表示网络数据流     */    @GET    fun getUserInfo(): Single}

这种建议有它的合理性,毕竟即使使用ObservableonNext也只会调用一次,根本不会再有Next。这篇文章就是要介绍,如何让数据流动起来,让网络数据流真的有Next数据,而不是无脑地再次发送网络请求。

1. 数据流动性需求是广泛存在的

先看几张图,它们描述了一种常见的设计:


首页 Android真响应式架构——数据流动性_第1张图片 个人中心 Android真响应式架构——数据流动性_第2张图片 消息列表

需求是一目了然的,消息的阅读状态决定了首页以及个人信息页中的显示状态,如果是你,你会怎么办?这是我面试中常问的一个问题。我听到最多的答案是,EventBus,或者广播。这些答案都体现了一种命令式更新的思想,发出一个命令,通知哪个哪个你该更新了。对于少数几个界面而言,这种方案也未尝不可。但是这种多个界面数据状态的联系在应用中是普遍存在的,满天飞的Event不是一个好的选择。
回头看看我们的需求,总结一下就是,数据可能因为用户的操作而发生变化,而这种数据变化应该体现在多个界面上。更抽象的说就是,数据是流动的,界面是响应式的。数据的流动性还是应该交由数据层解决。

2. 构建数据的联系

无论是使用Observable还是使用Single来表示网络数据流,网络数据都是一次性的,成功或者失败,然后数据流就会被切断。但是,有些时候数据的更新并不需要依赖于网络。例如,上面的例子中,假设我们清空了所有消息,只要这个网络请求成功了,我们就可以将用户的未读消息数设置为0。

再举个更加常见的例子

Android真响应式架构——数据流动性_第3张图片 用户中心 Android真响应式架构——数据流动性_第4张图片 个人资料

用户信息设置在各个应用中都非常常见。每一项设置都可能影响其它界面的显示状态,我们想让用户数据流动起来。

/** * Retrofit接口 */interface UserApi {    /**     * 获取用户信息     */    @GET    fun getUserInfo(): Observable>    /**     * 设置用户信息     */    @FormUrlEncoded    @POST    fun setUserInfo(@Field("nickname") nickname: String?,                    @Field("sex") gender: Int?,                    @Field("grade") gradeID: Int?,                    @Field("area") areaID: Int?,                    @Field("school") schoolID: Int?): Observable>}/*** 数据中间层* 对后台一个接口进行了拆分,分成若干个更加清晰明了的接口*/interface UserService {    fun getUserInfo(): Observable        fun setNickname(nickname: String): Observable    fun setGender(gender: Int): Observable    fun setGrade(gradeID: Int, name: String): Observable    fun setArea(areaID: Int, name: String): Observable    fun setSchool(schoolID: Int, name: String): Observable}/*** 数据中间层的实现类*/@Singletonclass UserClient @Inject constructor(    private val userApi: UserApi) : UserService {    //unwrapData方法在上一篇文章中提到过,用于获取想要的数据    override fun getUserInfo(): Observable =        userApi.getUserInfo().map(unwrapData())            override fun setNickname(nickname: String): Observable =        userApi.setUserInfo(nickname, null, null, null, null).map(unwrapData())    override fun setGender(gender: Int): Observable =        userApi.setUserInfo(null, gender, null, null, null).map(unwrapData())    override fun setGrade(gradeID: Int, name: String): Observable =        userApi.setUserInfo(null, null, gradeID, null, null).map(unwrapData())    override fun setArea(areaID: Int, name: String): Observable =        userApi.setUserInfo(null, null, null, areaID, null).map(unwrapData())    override fun setSchool(schoolID: Int, name: String): Observable =        userApi.setUserInfo(null, null, null, null, schoolID).map(unwrapData())}/** * 数据仓库 */@Singletonclass UserRepo @Inject constructor(    private val userClient: UserClient) : UserService by userClient {    //保存上次的用户数据    private lateinit var userInfo: UserInfo        //创建 Observable,可以多次发射 UserInfo数据    private lateinit var userInfoEmitter: ObservableEmitter    private val userInfoObservable: Observable by lazy {        Observable.create {            userInfoEmitter = it        }    }        //使用创建的 userInfoObservable,但是以网络数据userClient.getUserInfo()开始    //这样每次调用这个方法都会请求最新的网络数据,但又不会在网络请求结束时调用onComplete导致数据流被切断    override fun getUserInfo(): Observable =        userInfoObservable.startWith(userClient.getUserInfo())            .doOnNext {                userInfo = it            }        override fun setNickname(nickname: String): Observable =        userClient.setNickname(nickname)            .doOnComplete {                //设置了用户昵称,做出对应更新                if (::userInfoEmitter.isInitialized &&                    ::userInfo.isInitialized &&                    !userInfoEmitter.isDisposed                ) {                    userInfoEmitter.onNext(userInfo.copy(nickname = nickname))                }            }    //其它方法都是类似的...    }

注释中已经讲得很清楚了,关键就是用自定义的userInfoObservable代替原本的网络数据流,这样可以多次调用onNext方法,使用户数据得到对应更新。以这种方式,在数据仓库Repository中建立数据之间的联系,既体现出数据之间的联系性,又避免了满天飞的Event事件,还可以避免以startActivityForResult的方式建立的界面之间的联系。尘归尘,土归土,数据之间的联系还是应该在数据层去解决。

数据库ORM一般可以将数据的变动反应到数据库对外提供的Observable中,不需要我们额外处理。

总结

网络数据通常都是一次性的,结束之后数据流就会被切断,但是数据的流动性不应该局限于此,通过创建我们自己的Observable去替代原本的网络数据流,我们可以构建数据之间的广泛联系,使得数据流变成真正的数据流,而不仅仅是回调的一种变形。

更多相关文章

  1. 处女男学Android(十四)---Android 重量级数据存储之SQLite
  2. Android 用网络图片做帧动画
  3. android 通过广播监听网络连接状况
  4. android 网络拨号流程
  5. Android——数据存储(Login)
  6. android 读取串口数据的服务,android串口
  7. Android gson解析json数据工具类
  8. Android 网络链接,不要忘记添加网络权限。

随机推荐

  1. Android之网络丢包事件
  2. Android开发艺术探索——第十章:Android的
  3. Android面试系列文章2018之Android部分之
  4. 在Android中创建和使用数据库
  5. android扫描二维码(zxing)附带小例子
  6. Android防止内存溢出浅析
  7. Android(安卓)P 图形显示系统(九) Android
  8. android之调用webservice 实现图片上传
  9. 有关Android线程的学习
  10. Android内核开发:源码的版本与分支详解