Android 使用RxJava将本地数据与远程(或缓存)数据连接起来

Android 使用RxJava将本地数据与远程(或缓存)数据连接起来,android,rx-java,kotlin,rx-kotlin,Android,Rx Java,Kotlin,Rx Kotlin,这是一个有效的代码,但我有几个问题以及改进建议的请求。我是RxJava新手,我还没有完全了解如何将这些类型的观测值链接在一起 我有两个模型对象,ListItem和UserInfoListItems存在于本地数据库中,并且通过使用从ListItem提供的ID从服务器获取UserInfo UserInfoweb服务接受一个id数组,它将返回UserInfo对象列表 该代码的流程如下所示: 从数据库加载ListItems 使用从数据库中获取的ListItems,检查内存缓存,查看是否已获取特定List

这是一个有效的代码,但我有几个问题以及改进建议的请求。我是RxJava新手,我还没有完全了解如何将这些类型的观测值链接在一起

我有两个模型对象,
ListItem
UserInfo
ListItem
s存在于本地数据库中,并且通过使用从
ListItem
提供的ID从服务器获取
UserInfo

UserInfo
web服务接受一个id数组,它将返回
UserInfo
对象列表

该代码的流程如下所示:

  • 从数据库加载
    ListItem
    s
  • 使用从数据库中获取的
    ListItem
    s,检查内存缓存,查看是否已获取特定
    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) }
    }
    
  • 当前loadCachedUserInfo接收ListItem的数组,并在缓存项与之关联后返回与可观察数组相同的数组。我觉得这不对。相反,我认为这个调用应该只返回与缓存的UserInfo相关联的项目。但是,我需要继续将ListItem的完整数组传递给下一个方法
  • 我不确定我是否理解正确,但如果您只需要副作用(缓存),您可以使用
    doOnNext
    。比如说,

    .doOnNext { listItems ->
        if ( list.isUserList ) {
            cache(listItems, userIDIndex = list.userIDIndex!!)
        }
    }
    
    fun cache(listItems : List<ATListItem>, userIDIndex : Int) {
        // caching
    }
    
    可以这样写:

    .flatMap { listItems ->
        if ( list.isUserList )
            loadCachedUserInfo(listItems, userIDIndex = list.userIDIndex!!)
        else
            Observable.just(listItems)
    } 
    

    我没有测试代码。

    谢谢,doOnNext肯定是缺失的部分。我不再需要让我的缓存存储和查找成为一个可观察的方法,因为我可以在doOnNext中完成它们,这简化了一切。
    .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)
    }