如果你稍微改变一下思维方式,你的问题的解决方案实际上是非常简单和干净的。我正在使用完全相同的数据交互(Retrofit + Sqlbrite),并且该解决方案完美运行。
您所要做的就是使用两个单独的可观察订阅,它们负责完全不同的流程。
-
Database
->
View
: 这个是用来附加你的View
(Activity
, Fragment
或任何显示您的数据的内容)到数据库中的持久数据。您订阅一次即可创建View
.
dbObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
displayData(data);
}, throwable -> {
handleError(throwable);
});
-
API
->
Database
:另一种是从 api 获取数据并将其保存在数据库中。每次您想要刷新数据库中的数据时,您都需要订阅它。
apiObservable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(data -> {
storeDataInDatabase(data);
}, throwable -> {
handleError(throwable);
});
EDIT:
您不想将两个可观察量“转换”为一个,纯粹是因为您在问题中包含的原因。两个可观察量的行为完全不同。
The observable
来自 Retrofit 的作用就像Single http://reactivex.io/RxJava/javadoc/rx/Single.html。它做了它需要做的事情,并完成(与onCompleted
).
The observable
Sqlbrite 是一个典型的Observable
,每次特定表发生变化时它都会发出一些东西。理论上应该会在未来完成。
Ofc 你可以解决这个差异,但它会让你远离干净且易于阅读的代码。
如果你真的真的需要暴露一个observable
,你可以只hide事实上,当订阅数据库时,您实际上是在订阅来自改造的可观察数据。
- 将 Api 订阅包装在一个方法中:
public void fetchRemoteData() {
apiObservable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(data -> {
persistData(data);
}, throwable -> {
handleError(throwable);
});
}
-
fetchRemoteData
订阅中
dbObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(() -> fetchRemoteData())
.subscribe(data -> {
displayData(data);
}, throwable -> {
handleError(throwable);
});
我建议你认真考虑一下这一切。因为事实上,你强迫自己处于需要单个可观察值的位置,这可能会严重限制你。我相信这正是迫使你在未来改变你的观念的事情,而不是保护你免受改变本身的影响。