Subscribewith和subscribe在RxJava2(Android)中有何区别?

52

何时调用subscribeWith方法而不是普通的subscribe方法?使用场景是什么?

compositeDisposable.add(get()
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io())
    .subscribe(this::handleResponse, this::handleError));

对抗

   compositeDisposable.add(get()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
              //  .subscribe(this::handleResponse, this::handleError);
                .subscribeWith(new DisposableObserver<News>() {
                    @Override public void onNext(News value) {
                        handleResponse(value);
                    }

                    @Override public void onError(Throwable e) {
                        handleError(e);
                    }

                    @Override public void onComplete() {
                       // dispose here ? why? when the whole thing will get disposed later
                       //via  compositeDisposable.dispose();  in onDestroy();
                    }
                }));

谢谢


后来添加的

根据文档,两者都返回一次性SingleObserver实例:

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <E extends SingleObserver<? super T>> E subscribeWith(E observer) {
    subscribe(observer);
    return observer;
}

@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(final Consumer<? super T> onSuccess, final Consumer<? super Throwable> onError) {
    ObjectHelper.requireNonNull(onSuccess, "onSuccess is null");
    ObjectHelper.requireNonNull(onError, "onError is null");
    ConsumerSingleObserver<T> s = new ConsumerSingleObserver<T>(onSuccess, onError);
    subscribe(s);
    return s;
}

ConsumerSingleObserver类实现了SingleObserver和Disposable接口。


2
感谢@Simbatrons的回答,总结一下特定的使用情况(从我所理解的)是,如果您有一个相同的观察者,想要绑定到不同的可观察对象,请使用subscribeWith。(因此,多个可观察对象可以使用相同的观察者实现)。如果您认为这不是唯一的用例差异,请添加您的评论。 - bastami82
1
我也很好奇-在我看来,你的第一个片段使用lambda等更为简洁。所以,是的,似乎只有在想要重复使用相同的观察者时,您才需要使用.subscribeWith()?奇怪的是文档并没有真正提到返回Disposable的订阅的重载变体。相反,他们只指向使用新的且难以驾驭的subscribeWith()。 - Incinerator
1个回答

41

Observable#subscribe方法的解释:

在你的第一个代码片段中:

.subscribe(this::handleResponse, this::handleError));

实际上,你正在使用多个重载的Observable#subscribe方法之一:

public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)

还有另一个也可以接受Action来在完成时执行:

public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
        Action onComplete) {

还有一种选项,允许您简单地传递一个Observer (注意:这是void方法) (编辑2-此方法在ObservableSource中定义,而Observable扩展了该接口。)

public final void subscribe(Observer<? super T> observer)
在您的问题中的第二个代码片段中,您使用了subscribeWith方法,该方法仅返回您传递的Observer(方便/缓存等):

在你的问题中第二个代码片段中,你使用了 subscribeWith 方法,它仅仅是为了方便/缓存等,返回你传入的 Observer

public final <E extends Observer<? super T>> E subscribeWith(E observer)

Observer#onComplete 说明:

Observable 在流中发出所有项目后,将调用 Observer#onComplete。从 Java 文档中可以看到:

/**
 * Notifies the Observer that the {@link Observable} has finished sending push-based notifications.
 * <p>
 * The {@link Observable} will not call this method if it calls {@link #onError}.
 */
void onComplete();
因此,例如,如果您代码片段中的 get()返回发出多个 News 对象的 Observable ,则每个对象都将在 Observer#onNext 中处理。在这里,您可以处理每个项目。
在所有项目都处理完毕之后(并假设没有发生错误),然后将调用 onComplete 。在这里,您可以执行任何需要执行的其他操作(例如更新UI),因为您已经处理了所有 News 对象。
这与 Disposable#dispose 不同,后者在可观察流结束(完成/错误)时调用,或手动由您终止观察(这就是 CompositeDisposable 的作用,因为它帮助您一次性处置其中包含的所有 Disposable )。
如果在您的情况下 get()将返回仅发出单个项的 Observable ,则请考虑使用 io.reactivex.Single 而不是使用 Observable ,在 onSuccess 中只处理一个项目,并且不需要为onComplete指定 Action :) < p > 编辑:回应您的评论:

 

但是,我仍然不知道如何使用subscribeWith,您说它传递了观察者以进行缓存等,它传递到哪里?在完成时吗?从我所理解的subscribeWith实际上并没有消耗observable(或Single),对吗?

为了进一步澄清subscribeWith 的解释,我所说的是它消耗您传递给 subscribeWith Observer 对象(就像 subscribe 方法一样),但它还会将相同的Observer返回给您。在撰写本文时,subscribeWith的实现方式是:

public final <E extends Observer<? super T>> E subscribeWith(E observer) {
    subscribe(observer);
    return observer;
}

因此,subscribeWith 可以subscribe交替使用。

您能举一个使用subscribeWith的用例吗?我想这将完全回答这个问题

subscribeWith javadoc提供了以下使用示例:

Observable<Integer> source = Observable.range(1, 10);
CompositeDisposable composite = new CompositeDisposable();

ResourceObserver<Integer> rs = new ResourceObserver<>() {
     // ...
};

composite.add(source.subscribeWith(rs));

看这里,subscribeWith的用法会返回一个已实例化的ResourceObserver对象。这使得订阅和将ResourceObserver添加到CompositeDisposable可以在一行代码中完成(注意ResourceObservable实现了Disposable接口)。

Edit 2:回复第二条评论。

  

source.subscribeWith(rs); source.subscribe(rs); 都会返回SingleObserver实例,

ObservableSource#subscribe(Observer <? super T> observer) 不会 返回Observer。它是一个void方法(请参见上面Observable#subscribe说明下面的注释)。而Observable#subscribeWith 返回Observer。 如果我们使用ObservableSource#subscribe重写示例使用代码,则必须像下面这样分两行代码:

source.subscribe(rs); //ObservableSource#subscribe is a void method so nothing will be returned
composite.add(rs);

Observable#subscribeWith方法让我们可以方便地在一行代码中完成上述操作:composite.add(source.subscribeWith(rs));

然而,所有看起来相似的重载的subscribe方法可能会让人感到困惑,它们之间存在差异(有些是微妙的)。查看代码和文档有助于区分它们。


编辑3 subscribeWith的另一个示例用途

subscribeWith方法非常有用,当你有一个特定实现的Observer想要重用时。例如,在上面的示例代码中,它为订阅提供了一个特定的ResourceObserver实现,因此可以继承其功能,同时仍然允许您处理onNext、onError和onComplete。

另一个示例用途:对于您问题中的样本代码,如果您想要在多个位置执行与get()响应相同的订阅,该怎么办?

与其在不同的类中复制onNext和onError的Consumer实现,不如定义一个新类。

//sample code..
public class GetNewsObserver extends DisposableObserver<News> {
    //implement your onNext, onError, onComplete.
    ....
}

现在,每当您执行get()请求时,只需通过执行以下操作进行订阅:

compositeDisposable.add(get()
    ...
    .subscribeWith(new GetNewsObserver()));

看起来代码现在很简单,你保持了处理响应的责任分离,并且现在可以在需要的任何地方重用那个GetNewsObserver


1
添加了对答案的响应 :) - mmaarouf
1
source.subscribeWith(rs); source.subscribe(rs); 这两者都返回SingleObserver实例,因此可以互换使用,比如composite.add(one | another)。但为什么有人会选择使用其中一个而不是另一个对我来说仍然不清楚。如果我没有理解您的意思,请谅解,但我没有看到特定的用例,也就是说,在这种情况下,我们应该使用subscribeWith而不是subscribe。 - bastami82
1
source.subscribe(rs); 不返回观察者。我在答案的“编辑2”部分添加了进一步的解释。 - mmaarouf
1
不,你混淆了subscribe方法。我在Edit 2中使用的subscribe方法(以及subscribeWith的实现中使用的方法)将一个OBSERVER对象作为它的单个参数,并且是void方法。你提到的subscribe方法接受一个onSuccess CONSUMER对象和一个onError CONSUMER对象作为参数,并返回一个Disposable。注意不同的参数和返回类型?这是两种不同的方法。请重新阅读我答案中的Observable#subscribe解释部分,详细说明了不同的subscribe方法。 - mmaarouf
2
这完全取决于使用情况。如果您要订阅并在一个地方提供onNext、onError的独特实现,那么使用接受lambda表达式的#subscribe是有意义的。 否则,如果您需要在各种不同的类中重用常见的Observer代码,就像我在edit3中给出的示例或者像javadoc中的ResourceObservable示例一样,那么您可以使用#subscribeWith。使用最好解决问题的方法 :) - mmaarouf
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接