我有时必须在我的Observables中做一些清理任务(例如关闭打开的文件),我想知道什么是最好的方法。 到目前为止,我已经看过两个,但我很难理解他们的不同之处:你能解释一下这些差异吗?有没有更好的方法来实现这个目标?
1)
// MyObject will take care of calling onNext(), onError() and onCompleted()
// on the subscriber.
final MyObject o = new MyObject();
Observable obs = Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<? super Object> subscriber) {
try {
if (!subscriber.isUnsubscribed()) {
o.setSubscriber(subscriber);
// This will tell MyObject to start allocating resources and do its job.
o.start();
}
} catch (Exception e) {
subscriber.onError(e);
}
}
}).doOnUnsubscribe(new Action0() {
@Override
public void call() {
// This will tell MyObject to finish its job and deallocate any resources.
o.stop();
}
});
2)
Observable obs = Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<? super Object> subscriber) {
try {
if (!subscriber.isUnsubscribed()) {
// MyObject will take care of calling onNext(), onError() and onCompleted()
// on the subscriber.
final MyObject o = new MyObject(subscriber);
subscriber.add(Subscriptions.create(new Action0() {
@Override
public void call() {
// This will tell MyObject to finish its job and deallocate any resources.
o.stop();
}
}));
// This will tell MyObject to start allocating resources and do its job.
o.start();
}
} catch (Exception e) {
subscriber.onError(e);
}
}
});
答案 0 :(得分:2)
要回答原始问题,doOnUnSubscribe
和向Subscription
添加Subscriber
都是一样的。事实上,当您致电doOnUnSubscribe
时,只需将Action
作为Subscription
添加到您的Subscriber
。因此,doOnUnSubscribe
在后台使用了您的第二个示例。
doOnUnSubscribe
代码:
public class OperatorDoOnUnsubscribe<T> implements Operator<T, T> {
private final Action0 unsubscribe;
/**
* Constructs an instance of the operator with the callback that gets invoked when the modified Observable is unsubscribed
* @param unsubscribe The action that gets invoked when the modified {@link rx.Observable} is unsubscribed
*/
public OperatorDoOnUnsubscribe(Action0 unsubscribe) {
this.unsubscribe = unsubscribe;
}
@Override
public Subscriber<? super T> call(final Subscriber<? super T> child) {
child.add(Subscriptions.create(unsubscribe));
// Pass through since this operator is for notification only, there is
// no change to the stream whatsoever.
return Subscribers.wrap(child);
}
}
答案 1 :(得分:1)
您提到的两个解决方案中使用 的决定取决于您尝试使用/关闭/部署的资源是否要在多个订阅之间共享 即可。
使用资源生成事件时,使用 subscriber.add(...)。在这种情况下,您不希望共享资源。
MyObject
的示例就是这种情况。这样做的好处是资源不会在Observable.create()
方法之外暴露,从而使资源免于意外的副作用。当您必须在多个订阅中共享内容时,请使用 doOnUnsubscribe 。
doOnUnsubscribe
或doOnSubscribe
中递增。 doOnSubscribe
和doOnUnsubscribe
中相应地使用递增和递减组合来实现该目的。 同样在您的示例中,您可以使用MyObject
方法替换它来管理资源的打开和关闭以及生成事件,而不是创建Observable.using()
抽象,以实现相同的目标。它有三个参数:
resourceFactory
,将打开资源observableFactory
,将生成事件和disposeAction
,将关闭资源答案 2 :(得分:0)
如果你没有在subscriber.onNext下面放置任何值,那么使用Observable.create有什么意义呢?
第一个是一个巨大的禁忌,因为你正在为一个被关闭的物体做副作用。如果您同时从两个不同的线程订阅创建的observable会发生什么?
第二个看起来更好,因为你添加了subscriber.add,如果已经处理了订阅,它将调用o.stop()。唯一缺少的是onNext的调用,该值遍历下游。
有一个运算符用于从资源创建Observables,称为“using”。请查看http://reactivex.io/RxJava/javadoc/rx/Observable.html#using(rx.functions.Func0,%20rx.functions.Func1,%20rx.functions.Action1)
答案 3 :(得分:0)
如果你可以提供帮助,首先不要使用Observable.create(OnSubscribe)
,因为你可以很容易地破解东西(比如背压或可观察合同相关的东西)。您应该使用许多静态工厂方法之一。
除了直接解决您的问题外,我建议Observable.using
明确设计为在终止或取消订阅时释放资源。
例如:
Observable<byte[]> bytes =
Observable.using(
() -> new FileInputStream(file), //resource factory
is -> Bytes.from(is), // observable factory
is -> is.close() // close action
);
如果您使用RxJava 2,上面的示例会错过一些不会出现的尝试捕获(例如is.close()
左右)。
试图充实你的案子:
Observable.using(
() -> new MyObject(), //resource factory
myObject -> makeObservable(myObject), // observable factory
myObject -> myObject.stop() // close action
);