android-使用RxJava将本地数据与远程(或缓存)数据连接
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了android-使用RxJava将本地数据与远程(或缓存)数据连接,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6962字,纯文字阅读大概需要10分钟。
内容图文
这是有效的代码,但是我有几个问题以及关于改进它的建议.我是RxJava的新手,我还没有完全了解如何将这些类型的可观察对象链接在一起.
我有两个模型对象,ListItem和UserInfo. ListItems存在于本地数据库中,并且使用从ListItem提供的ID从服务器获取UserInfo.
UserInfo Web服务接受ID数组,将为其返回UserInfo对象列表.
这段代码的流程如下:
>从数据库加载ListItems
>使用从数据库中获取的ListItem,检查内存中的缓存以查看是否已经获取了特定ListItem的UserInfo
>对于未缓存UserInfo的任何项目,请从网络中获取它们
>将获取的UserInfo对象放入缓存
>重新运行步骤2(方法为loadCachedUserInfo)
>将结果返回给订户
注意:仅当列表被视为isUserList时,才应为ListItem提取UserInfo对象.
这是代码:
fun itemsInList(list : ATList, parentValue : String? = null, searchString : String? = null, limit : Int = defaultFetchLimit, sortOrder: SortDescriptor? = null) : Observable<List<ATListItem>> {
return Observable.create<List<ATListItem>> { subscriber ->
val listItems = listItemsInList(list, parentValue = parentValue, searchString = searchString, limit = limit, sortOrder = sortOrder)
subscriber.onNext(listItems)
subscriber.onCompleted()
}.flatMap { listItems ->
if ( list.isUserList ) {
return@flatMap loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
}
return@flatMap Observable.just(listItems)
}.flatMap { listItems ->
if ( list.isUserList ) {
return@flatMap fetchUserInfoForListItems(listItems, list.userIDIndex!!, force = false)
}
return@flatMap Observable.just(listItems)
}
}
fun loadCachedUserInfo(listItems : List<ATListItem>, userIDIndex : Int) : Observable<List<ATListItem>> {
return Observable.create<List<ATListItem>> { subscriber ->
for ( listItem in listItems ) {
listItem.coreUserInfo = coreUserMap[listItem.valueForAttributeIndex(userIDIndex)?.toLowerCase()]
}
subscriber.onNext(listItems)
subscriber.onCompleted()
}
}
fun fetchUserInfoForListItems(listItems : List<ATListItem>, userIDIndex: Int, force: Boolean) : Observable<List<ATListItem>> {
val itemsToFetch = if ( force ) listItems else listItems.filter { it.coreUserInfo == null }
val ids = itemsToFetch.map { it.valueForAttributeIndex(userIDIndex) ?: "" }.filter { !it.isEmpty() }
val records = hashMapOf("records" to ids)
if ( itemsToFetch.count() == 0 ) {
return Observable.just(listItems)
}
return RuntimeDataController.dataService.fetchCoreUserInfo(recordsMap = records)
.map { json ->
val recordsArray = json.arrayValue("records")
for ( i in 0..recordsArray.length() - 1) {
val coreUserInfo = CoreUserInfo(recordsArray.getJSONObject(i))
coreUserMap[coreUserInfo.username.toLowerCase()] = coreUserInfo
coreUserMap[coreUserInfo.userID] = coreUserInfo
coreUserInfo.externalUserID?.let { coreUserMap[it] = coreUserInfo }
}
return@map listItems
}.flatMap { loadCachedUserInfo(listItems, userIDIndex = userIDIndex) }
}
用户可以通过调用以下命令来启动事件序列:
ListController.itemsInList(列表)
我对此代码的疑问是:
>当前,loadCachedUserInfo接收一个ListItem数组,并在与缓存项相关联后返回与可观察到的数组相同的数组.我觉得这很不对.我认为相反,此调用应仅返回与之关联的已缓存UserInfo的项目.但是,我需要继续将ListItem的完整数组传递给下一个方法
2.)我需要做其他工作来支持退订吗?
3.)这是类似的问题1.我的fetchUserInfoForListItems提取一个列表项数组,并在获取并通过cache方法重新运行它们之后返回与该列表项数组相同的Observable.这对我来说也感觉不正确.我希望该方法返回一个Observable< List< UserInfo>>.用于获取的对象.我不明白如何在itemsInList中然后将ListItems与新获取的UserInfo关联并返回这些ListItems的Observable.
编辑:写完这篇文章后,它给了我一些帮助.我可以将flatMap的调用包装到一个Observable.create中,其中可以包含我想从fetchUserInfoForListItems中取出的智能,让我解决问题#3.这是更新的代码:
fun itemsInList(list : ATList, parentValue : String? = null, searchString : String? = null, limit : Int = defaultFetchLimit, sortOrder: SortDescriptor? = null) : Observable<List<ATListItem>> {
return Observable.create<List<ATListItem>> { subscriber ->
val listItems = listItemsInList(list, parentValue = parentValue, searchString = searchString, limit = limit, sortOrder = sortOrder)
subscriber.onNext(listItems)
subscriber.onCompleted()
}.flatMap { listItems ->
if ( list.isUserList ) {
return@flatMap loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
}
return@flatMap Observable.just(listItems)
}.flatMap { listItems ->
if ( list.isUserList ) {
return@flatMap Observable.create<List<ATListItem>> { subscriber ->
fetchUserInfoForListItems(listItems, list.userIDIndex!!, force = false).map { userInfoList ->
for (coreUserInfo in userInfoList) {
coreUserMap[coreUserInfo.username.toLowerCase()] = coreUserInfo
coreUserMap[coreUserInfo.userID] = coreUserInfo
coreUserInfo.externalUserID?.let { coreUserMap[it] = coreUserInfo }
}
}.flatMap {
loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
}.subscribe {
subscriber.onNext(listItems)
subscriber.onCompleted()
}
}
}
return@flatMap Observable.just(listItems)
}
}
fun loadCachedUserInfo(listItems : List<ATListItem>, userIDIndex : Int) : Observable<List<ATListItem>> {
return Observable.create<List<ATListItem>> { subscriber ->
listItems.forEach { listItem -> listItem.coreUserInfo = coreUserMap[listItem.valueForAttributeIndex(userIDIndex)?.toLowerCase()] }
subscriber.onNext(listItems)
subscriber.onCompleted()
}
}
fun fetchUserInfoForListItems(listItems : List<ATListItem>, userIDIndex: Int, force: Boolean) : Observable<List<CoreUserInfo>> {
val itemsToFetch = if ( force ) listItems else listItems.filter { it.coreUserInfo == null }
val ids = itemsToFetch.map { it.valueForAttributeIndex(userIDIndex) ?: "" }.filter { !it.isEmpty() }
val records = hashMapOf("records" to ids)
if ( itemsToFetch.count() == 0 ) { return Observable.just(ArrayList<CoreUserInfo>()) }
return RuntimeDataController.dataService.fetchCoreUserInfo(recordsMap = records)
.map { json ->
val userInfo = ArrayList<CoreUserInfo>()
json.arrayValue("records").eachObject { userInfo.add(CoreUserInfo(it)) }
return@map userInfo
}
}
解决方法:
- Currently loadCachedUserInfo takes in an array of ListItem and returns that same array as an observable after the cached items have been associated with it. This feels wrong to me. I think instead this call should only return the items that have a cached UserInfo associated with it. However, I need to continue passing the full array of ListItem to the next method
我不确定我是否正确理解您,但是如果您只需要副作用(缓存),则可以使用doOnNext.例如,
.doOnNext { listItems ->
if ( list.isUserList ) {
cache(listItems, userIDIndex = list.userIDIndex!!)
}
}
fun cache(listItems : List<ATListItem>, userIDIndex : Int) {
// caching
}
- Do I need to do additional work to support unsubscribing?
不,AFAIK.
注意:
有关doOnNext的更多信息,请参见What is the purpose of doOnNext(…) in RxJava和here.
通常,如果lambda中的最后一条语句是表达式,则不需要return @….
例如.:
.flatMap { listItems ->
if ( list.isUserList ) {
return@flatMap loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
}
return@flatMap Observable.just(listItems)
}
可以这样写:
.flatMap { listItems ->
if ( list.isUserList )
loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
else
Observable.just(listItems)
}
我没有测试代码.
内容总结
以上是互联网集市为您收集整理的android-使用RxJava将本地数据与远程(或缓存)数据连接全部内容,希望文章能够帮你解决android-使用RxJava将本地数据与远程(或缓存)数据连接所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。