3

这是我的用例:

我正在开发一个应用程序,它通过 REST API 与服务器通信,并将接收到的数据存储在 SQLite 数据库中(它使用它作为某种缓存)。

当用户打开屏幕时,必须发生以下情况:

  1. 如果可用,则从数据库加载数据。
  2. 应用调用 API 刷新数据。
  3. API 调用的结果被持久化到数据库中。
  4. 当数据更改通知被拦截时,数据会从数据库中重新加载。

这与此处介绍的情况非常相似,但略有不同。

由于我使用的是 SQLBrite,因此 DB observables 不会终止(因为那里有一个ContentObserver注册,它将新数据推送到流中),所以像这样的方法concatmerge不起作用。

目前,我已经使用以下方法解决了这个问题:

Observable.create(subscriber -> {
    dbObservable.subscribe(subscriber);
    apiObservable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(
            (data) -> {
                try {
                    persistData(data);
                } catch (Throwable t) {
                    Exceptions.throwOrReport(t, subscriber);
                }
            },

            (throwable) -> {
                Exceptions.throwOrReport(throwable, subscriber);
            })
})

看起来它工作正常,但它看起来并不优雅和“正确”。

您能否建议或指出一个资源来解释处理这种情况的最佳方法是什么?

4

1 回答 1

6

如果你稍微改变一下思维方式,你的问题的解决方案实际上是非常简单和干净的。我正在使用完全相同的数据交互(Retrofit + Sqlbrite),并且该解决方案完美运行。

您需要做的是使用两个独立的可观察订阅,它们处理完全不同的过程。

  1. Database -> View:这个用于将您的(View或任何显示您的数据)附加到数据库中的持久数据。您为 created 订阅一次。ActivityFragmentView

dbObservable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(data -> {
            displayData(data);
        }, throwable -> {
            handleError(throwable);
        });
  1. API -> Database:另一个从 api 获取数据并将其保存在数据库中。每次要刷新数据库中的数据时,都需要订阅它。

apiObservable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(data -> {
           storeDataInDatabase(data);
        }, throwable -> {
            handleError(throwable);
        });

编辑:

您不想将两个可观察值“转换”为一个,纯粹是因为您在问题中包含的原因。两个 observables 的行为完全不同。

from Retrofit的observable作用类似于Single. 它做它需要做的事情,并完成(用onCompleted)。

observablefrom Sqlbrite 是一个典型的,Observable每次特定表更改时它都会发出一些东西。理论上它应该在未来完成。

Ofc 你可以解决这个差异,但它会让你远离干净且易于阅读的代码。

如果你真的,真的需要公开一个单一的observable,你可以在订阅你的数据库时隐藏你实际上订阅了可观察到的改造的事实。

  1. 将 Api 订阅包装在一个方法中:

public void fetchRemoteData() {
    apiObservable
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .subscribe(data -> {
                persistData(data);
            }, throwable -> {
                handleError(throwable);
            });
}
  1. fetchRemoteData订阅时

dbObservable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .doOnSubscribe(() -> fetchRemoteData())
        .subscribe(data -> {
            displayData(data);
        }, throwable -> {
            handleError(throwable);
        });

我建议你真的考虑一下这一切。因为您强迫自己进入需要单个可观察对象的位置这一事实可能会严重限制您。我相信这将是迫使你在未来改变你的概念的确切事情,而不是保护你免受改变本身的影响。

于 2017-01-10T15:29:25.547 回答