2016-03-02 183 views
21

我有一个关于如何取消订阅observable的问题。我有两个代码,我不确定哪一个更好。何时取消订阅

例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的更多呼叫。

哪一个更好?

在此先感谢

+0

我有麻烦让我的代码(用拉来刷新)刷新第二次时使用拉刷新监听器。我已经验证我的拉动刷新工作正常,但第二套“observable.subscribeOn(Schedulers.newThread())。observeOn(AndroidSchedulers.mainThread())。subscribe(subscriber)”不工作,只有第一套。有任何想法吗? – lawonga

回答

21

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

在您的第一个示例中,您在onComplete()方法中不需要unsubscribing。如果您到达订阅的onComplete(),则您不再有退订的责任。

你的第二个例子是正确的。 CompositeSubscription背后的想法是,您可以添加多个Subscriptions,然后立即清理(unsubscribe)。换句话说,这只需要保留需要退订的Subscriptions列表即可。

使用CompositeSubscription一个棘手的部分是,如果你曾经unsubscribe它,你可以不是再次使用它。您可以查看compositeSubscription.add()方法的文档以获取详细信息。简而言之 - 它会直接取消订阅您要添加的订阅。这是一个慎重的决定(你可以阅读更多关于它HERE)。

回到你的例子,在onDestroy()的Activity中调用unsubscribe()就可以了,并且可以节省内存泄漏。关于您在多次拨打test()方法时发生问题的评论 - 我会说您的问题在其他地方。也许你的用例不应该多次调用它,也许你应该在使用新接收的数据之前清理旧数据等等。也许如果你已经详细解释了你面临的问题,我们可以帮助更多。但就CompositeSubscription而言 - 您正在使用它并正确取消订阅!

+7

但'onDestroy'不保证被调用。这是否意味着如果因为某种原因未调用'onDestroy',将会出现内存泄漏,因为在这种情况下'unsubscribe'不会被调用? – Storix

+0

既然你的'Observable'只发出一个项目,为什么不使用'Single'呢?它不是'onNext()',而是一次调用'SingleSubscriber'的'onSuccess()',然后完成(没有'onComplete()'调用)。 –

3

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

我总是在退订的onDestroy()

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

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

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

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(); 
} 
+0

在示例2中,您必须声明与在活动中使用的订阅(成员变量)相同的许多订阅(成员变量),并且在销毁时取消订阅它们,对吧? – MarcForn

+0

@MarcForn检查我的编辑 –

+0

在我的项目中,我正在使用CompositeSubscription,并在测试方法中将订阅添加到CompositeSubscription。我发现的问题(这是该帖子的原因)是关于多次调用测试方法。这样做,我意识到我们有n订阅(相同)添加到CompositeSubscription列表。 – MarcForn

24

没有必要在onCompleted退订。看看The Observable Contract

当可观察到的问题进行的OnError或通知的onComplete其 观察员,这结束认购。观察者不需要以这种方式发出 退订通知以结束由 Observable结尾的订阅。

另一方面,您绝对应该退订onDestroy以防止内存泄漏。