何时退订订阅服务

33

我有一个问题,关于如何取消可观察对象的订阅。我有两个代码示例,但不确定哪个更好。

示例1 - 在流完成后取消订阅:

Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            progressdialog.dissmiss();
            unsubscribe();
        }

        @Override
        public void onError(Throwable e) {
            progressdialog.dissmiss();
        }

        @Override
        public void onNext(String s) {
            // do something with data
        }
    }

示例2 -> 一旦活动被销毁,取消订阅订阅:

private void test(){
    Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            progressdialog.dissmiss();
        }

        @Override
        public void onError(Throwable e) {
            progressdialog.dissmiss();
        }

        @Override
        public void onNext(String s) {
            // do something with data
        }
    };

    subscription = BackendRequest.login(loginRequest)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);

    compositeSubscription.add(subscription);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    this.subscription.unsubscribe();
}

我必须提到我的观察对象只会发出一次,活动不应该等待Observable的更多调用。

哪个更好?

提前致谢。


我在使用下拉刷新监听器时,我的代码(带有下拉刷新)在第二次刷新时遇到了问题。我已经验证了我的下拉刷新是否正常工作,但第二组“observable.subscribeOn(Schedulers.newThread())。observeOn(AndroidSchedulers.mainThread())。subscribe(subscriber)”不起作用,只有第一组。有什么想法吗? - lawonga
3个回答

29

onCompleted中不需要取消订阅。请查看Observable合同

当Observable向其观察者发出OnError或OnComplete通知时,这将结束订阅。以这种方式结束的订阅无需观察者发出取消订阅通知来结束订阅。

另一方面,您应该在onDestroy中取消订阅,以防止内存泄漏。


29

从这两个选项中,第二个更好。

在您的第一个示例中,您在不需要的onComplete()方法中执行了取消订阅操作。如果到达Subscription的onComplete(),则您不再有责任取消对其的订阅。

您的第二个示例是正确的。使用CompositeSubscription的想法是可以将多个Subscription添加到其中,然后一次性清除(unsubscribe)。换句话说,这只是使您无需保留需要取消订阅的Subscriptions列表。

使用CompositeSubscription的一个棘手部分是,如果您一旦unsubscribe,就无法再次使用它。您可以查看compositeSubscription.add()方法的文档以了解详细信息。简而言之-它将直接取消订阅您正在尝试添加的Subscription。这是一个故意的决定(您可以在此处阅读更多信息)。

回到您的示例,在Activity的onDestroy()中调用unsubscribe()是正确的,并且可以避免内存泄漏。关于您的评论,即在多次调用test()方法时出现问题-我会说您的问题可能出在其他地方。也许您的用例不允许多次调用它,也许在使用新接收的数据之前应清除旧数据等。也许如果您详细解释了遇到的问题,我们可以提供更多帮助。但就CompositeSubscription而言-您正在正确使用它并取消订阅它!


10
但是 onDestroy 不一定会被调用。这是否意味着如果由于某些原因未调用 onDestroy,那么会因为也没有调用 unsubscribe 而导致内存泄漏? - Stan Mots
1
既然你的Observable只发出一个项目,为什么不使用Single呢?它不是调用onNext(),而是一次调用SingleSubscriberonSuccess(),然后就完成了(没有onComplete()调用)。 - Robert Lewis

5

我认为这取决于你的需求。如果该活动不会等待任何其他调用,我想你可以在onCompleted()中取消订阅。

我总是在onDestroy()中取消订阅。

@Override
protected void onDestroy() {
    super.onDestroy();

    if (subscription != null) {
        subscription.unsubscribe();
    }
}

编辑:请查看http://reactivex.io/RxJava/javadoc/rx/subscriptions/CompositeSubscription.html


(建议阅读RxJava文档)
private CompositeSubscription mCompositeSubscription = new CompositeSubscription();

private void doSomething() {
    mCompositeSubscription.add(
        AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))
       .subscribe(s -> System.out.println(s)));
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mCompositeSubscription.unsubscribe();
}

在示例2中,您必须声明与活动中使用的订阅(成员变量)一样多的订阅,并在onDestroy函数中取消订阅所有订阅,对吗? - MarcForn
在我的项目中,我使用CompositeSubscription,并在测试方法中将订阅添加到CompositeSubscription中。我发现的问题(这就是发布的原因)是关于多次调用测试方法的问题。这样做,我意识到我们已经将n个订阅(相同的)添加到CompositeSubscription列表中。 - MarcForn
@MarcForn 抱歉,我不理解.. 你想编辑帖子并解释测试问题吗?也许我可以帮忙。 - Matias Elorriaga
是的,问题出现在我多次调用测试方法时,例如在“下拉刷新”中调用。因此,CompositeSubscription会一遍又一遍地增加。您如何正确取消订阅? - MarcForn

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