Android开发人口流动管理,Android真响应式架构——数据流动性

前言

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

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

/**

* Retrofit接口

*/

interface UserApi {

/**

* 获取用户信息

* 使用 Observable表示网络数据流

*/

@GET

fun getUserInfo(): Observable

/**

* 获取用户信息

* 使用 Single表示网络数据流

*/

@GET

fun getUserInfo(): Single

}

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

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

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

941b7f3e738c

首页

941b7f3e738c

个人中心

941b7f3e738c

消息列表

需求是一目了然的,消息的阅读状态决定了首页以及个人信息页中的显示状态,如果是你,你会怎么办?这是我面试中常问的一个问题。我听到最多的答案是,EventBus,或者广播。这些答案都体现了一种命令式更新的思想,发出一个命令,通知哪个哪个你该更新了。对于少数几个界面而言,这种方案也未尝不可。但是这种多个界面数据状态的联系在应用中是普遍存在的,满天飞的Event不是一个好的选择。

回头看看我们的需求,总结一下就是,数据可能因为用户的操作而发生变化,而这种数据变化应该体现在多个界面上。更抽象的说就是,数据是流动的,界面是响应式的。数据的流动性还是应该交由数据层解决。

2. 构建数据的联系

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

再举个更加常见的例子

941b7f3e738c

用户中心

941b7f3e738c

个人资料

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

/**

* 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

}

/**

* 数据中间层的实现类

*/

@Singleton

class 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())

}

/**

* 数据仓库

*/

@Singleton

class 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去替代原本的网络数据流,我们可以构建数据之间的广泛联系,使得数据流变成真正的数据流,而不仅仅是回调的一种变形。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值