这是工作代码,但我有一些问题以及有关改进它的建议请求。我是RxJava的新手,我还没有完全理解如何将这些类型的可观察链连接在一起。
我有两个模型对象ListItem
和UserInfo
。 ListItem
存在于本地数据库中,并使用UserInfo
提供的ID从服务器获取ListItem
。
UserInfo
Web服务接受一组ID,它将返回UserInfo
个对象的列表。
此代码的流程如下:
ListItem
ListItem
,检查内存缓存,看看我是否已为特定UserInfo
提取ListItem
UserInfo
的任何项目,请从网络中提取UserInfo
个对象放入缓存loadCachedUserInfo
)注意:如果列表被视为UserInfo
,则只应为ListItem
提取isUserList
个对象。
以下是代码:
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(list)
我对此代码的疑问是:
loadCachedUserInfo
接收ListItem
数组,并在缓存项与之关联后返回与observable相同的数组。这对我来说不合适。我认为此调用只应返回与其关联的缓存UserInfo
的项目。但是,我需要继续将完整的ListItem
数组传递给下一个方法2。)我是否需要做额外的工作来支持取消订阅?
3。)这是类似的问题1.我的fetchUserInfoForListItems
获取一个列表项数组,并在获取并重新运行缓存方法后返回具有相同列表项数组的observable。这对我来说也不合适。我宁愿这个方法为被提取的对象返回Observable<List<UserInfo>>
。我不理解itemsInList
如何将ListItem
s与新提取的UserInfo
相关联,并返回ListItem
s的Observable。
编辑:撰写此帖后,它帮助我实现了一些目标。我可以在一个Observable.create中使用flatMap包装我的调用,它可以包含我想从我的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
}
}
答案 0 :(得分:3)
- 目前,loadCachedUserInfo接收ListItem数组,并在缓存项与之关联后返回与observable相同的数组。这对我来说不合适。我认为此调用应该只返回具有与之关联的缓存UserInfo的项目。但是,我需要继续将ListItem的完整数组传递给下一个方法
醇>
我不确定我是否理解正确,但如果您只需要副作用(缓存),则可以使用doOnNext
。例如,
.doOnNext { listItems ->
if ( list.isUserList ) {
cache(listItems, userIDIndex = list.userIDIndex!!)
}
}
fun cache(listItems : List<ATListItem>, userIDIndex : Int) {
// caching
}
- 我是否需要做额外的工作来支持取消订阅?
醇>
不,AFAIK。
注意:强>
有关doOnNext
的更多信息,请访问What is the purpose of doOnNext(...) in RxJava和here
通常,如果lambda中的最后一个语句是表达式,则不需要return@...
。
e.g:
.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)
}
我没有测试代码。