无论订阅者如何,Observer
如何使其逻辑执行一次(异步)。我的用例是Provider
类,它通过委托给另一个对象(Model
)来为SqliteOpenHelper
类做CRUD。无论UI是否订阅,对ModelProvider.update
的调用都应该保持对模型的更改。
class ModelProvider {
Observable<String> updateModel(Model model) {
return Observable.create((Subscriber<? super String> subscriber) -> {
// synchronous for now, probably irrelevant
String modelId = repository.save(model);
subscriber.onNext(modelId);
}).subscribeOn(Schedulers.io());
}
}
class SomeActivity {
void updateModel(Model model) {
// dont care about the result, but need it to execute exactly once
mModelProvider.updateModel(model);
}
}
我正在将代码库移动到使用RxJava和反应模式,因此对repository.save(model)
的调用是同步的,但是仍然需要逻辑在之后执行一次,无论是否有UI订阅者。< / p>
我考虑过简单地将存储库逻辑移出observable,然后返回一个使用该结果的不同observable:
class ModelProvider {
Observable<String> updateModel(Model model) {
String modelId = repository.save(model);
return Observable.create((Subscriber<? super String> subscriber) -> {
subscriber.onNext(modelId);
}).subscribeOn(Schedulers.io());
}
}
但这会强制IO在主线程上工作并阻止它。
另一个非解决方案:
Observable<String> updateModel(Model model) {
Observable<String> obs = Observable.create((Subscriber<? super String> subscriber) -> {
String modelId = repository.save(model);
subscriber.onNext(modelId);
}).subscribeOn(Schedulers.io());
obs.subscribe();
return obs;
}
这会在obs.subscribe()
执行一次,但如果UI订阅它则会再次执行。
我刚刚学习反应模式,但我认为这是Subjects
/ Relays
有用的地方。
答案 0 :(得分:1)
这有效:
Observable<String> updateModel(Model model) {
Observable<String> obs = Observable.create((Subscriber<? super String> subscriber) -> {
String modelId = repository.save(model);
subscriber.onNext(modelId);
}).subscribeOn(Schedulers.io())
// cached() returns a new observer over the original, which only executes once
// but not until it is subscribed to
Observable<String> cachedObs = obs.cache();
// this "starts" execution of `repository.save()`
cachedObs.subscribe();
// return observable that executes once and caches (cachedObs)
// returning the original (obs) would cause multiple executions
return cachedObs;
}
创建后调用Observable.cache()
会阻止重新调用,但需要调用obs.subscribe()
才能获得 one-and-one-one 调用。
请注意,持久性块(repository.save()
等...)在订阅时不会立即启动,而是排队在不确定点上的单独线程(Schedulers.io
线程池)上异步执行在将来。
这使用rxjava-async-utils
包并且也有效:
Observable<String> updateModel(Model model) {
Observable<String> obs = Async.start(() -> repository.save(model));
// cached() here is required in order to avoid the race condition
Observable<String> cachedObs = obs.cache();
return cachedObs;
}
请注意,需要调用cache()
才能保存结果并将其提供给订阅者。没有它,就会出现一种竞争条件,即订阅者没有结果,因为Async.start
块已经完成。
答案 1 :(得分:1)
正如@xst所说,但我更加简化:
return Observable
.defer(() -> Observable.just(repository.save(model)))
.subscribeOn(Schedulers.io())
.cache();