【问题标题】:How do I make my app fetch from local if there is no connectivity and from remote if there is?如果没有连接,如何从本地获取我的应用程序,如果有,如何从远程获取?
【发布时间】:2018-09-01 01:46:04
【问题描述】:

我的MainRepository 是从 API 获取数据并插入数据库,然后显示在 UI 上的。

override fun fetchAll() {
    Observable.fromCallable { local.fetchPosts() }
        .doOnNext {
            remote.fetchPosts().concatMap { posts ->
                local.insert(*posts.toTypedArray())
                Observable.just(posts)
            }
        }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            { outcome.success(it) },
            { error: Throwable -> outcome.failed(error) }
        ).addTo(compositeDisposable)
}

outcome 变量是PublishObject 类型的Response,即LoadingSuccessFailure

override val outcome = PublishSubject.create<Response<List<Post>>>()

[...]

sealed class Response<T> {
    companion object {
        fun <T> loading(loading: Boolean): Response<T> = Progress(loading)
        fun <T> success(data: T): Response<T> = Success(data)
        fun <T> failure(e: Throwable): Response<T> = Failure(e)
    }

    data class Progress<T>(var loading: Boolean) : Response<T>()
    data class Success<T>(var data: T) : Response<T>()
    data class Failure<T>(var e: Throwable) : Response<T>()
}

它执行一个方法local.fetchPosts(),这是一个负责访问DAO函数的函数。

fun fetchPosts() = database.postDao().fetchAll()

[...]

@Query("SELECT * FROM posts ORDER BY createdAt DESC")
fun fetchAll(): List<Post>

addToDisposable 的扩展:

fun Disposable.addTo(compositeDisposable: CompositeDisposable) {
    compositeDisposable.add(this)
}

我尝试在Observable.fromCallable 之后使用concatMap,但它会直接显示来自API 的数据,而doOnNext 会从数据库中显示,但它不会更新列表,删除已删除的内容远程服务器。

【问题讨论】:

    标签: android rx-java2 android-room android-architecture-components


    【解决方案1】:

    首先您必须了解doOnNextSide Effect Operator,以及它的家族,副作用运算符仅预测执行次要操作(例如记录)的排放,它们不会影响流无论如何。

    所以,你正在做可观察的

    remote.fetchPosts().concatMap { posts ->
                local.insert(*posts.toTypedArray())
                Observable.just(posts)
            }
    

    永远不会开始工作,因为它没有被订阅。 现在您必须根据您想要的行为做出决定,我假设您的用例是:

    • 尝试从 API 获取数据。

    • 缓存成功,不查询DAO

    • 显示它

    然后这样的事情会起作用:

    remote.fetchPosts()
        // cache the data from remote.
        .doOnNext(posts -> local.insert(*posts.toTypedArray()))
        // if an error happens, use the posts in the DAO.
        .onErrorResumeNext { Observable.fromCallable { local.fetchPosts() } }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        [...]
    

    【讨论】:

    • onErrorResumeNext 有一个错误提示“重载分辨率歧义。所有这些函数都匹配”。 subscribeit 上也显示错误,说它的引用未解决。我省略了其余的代码,因为我认为这是不必要的,但显然,这很重要。我更新了完全显示它的问题。我尝试改用doOnError,但它不起作用。
    • doOnError 中获取本地数据的方法似乎不起作用,就像我在顶部调用一样。
    • 我现在已经修好了。 onErrorResumeNext 需要 _: Throwable
    • 很有趣,它解决了我遇到的另一个问题,而不是问题标题中描述的问题。我将相应地重命名并打开一个新的,因为关于清洁底座的问题仍然存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多