2016-03-02 184 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以防止內存泄漏。