2016-03-02 33 views
21

Ho una domanda su come annullare l'iscrizione di un osservabile. Ho due codici e non sono sicuro di quale sia il migliore.Quando annullare l'iscrizione a un abbonamento

Esempio 1 -> Cancellati l'abbonato una volta che il flusso è terminato:

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 
     } 
    } 

Esempio 2 -> annullare la sottoscrizione una volta che l'attività è distrutto:

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

devo menzionare che il mio gli osservabili emetteranno solo una volta, l'attività non dovrebbe attendere più chiamate dall'osservabile.

Quale è il migliore?

Grazie in anticipo

+0

Ho problemi ad ottenere il mio codice (con pull da aggiornare) per aggiornare una seconda volta quando si utilizza pull per aggiornare il listener. Ho verificato che il mio pull per aggiornare funzioni correttamente, ma il secondo set di "observable.subscribeOn (Schedulers.newThread()). ObservOn (AndroidSchedulers.mainThread()). Subscribe (subscriber)" non funziona, solo il primo. Qualche idea? – lawonga

risposta

21

Dalle due opzioni la seconda è migliore.

Nel tuo primo esempio sei unsubscribing nel metodo onComplete() che non è necessario. Se raggiungi lo onComplete() di un Abbonamento, non hai più la responsabilità di cancellarti dall'iscrizione.

Il tuo secondo esempio è quello corretto. L'idea alla base dello CompositeSubscription è che è possibile aggiungere più Subscriptions e poi ripulire (unsubscribe) in una sola volta. In altre parole, questo ti evita semplicemente di tenere un elenco di Subscriptions di cui hai bisogno per annullare l'iscrizione.

Una parte difficile utilizzando CompositeSubscription è che se una volta unsubscribe, è possibile NON utilizzare di nuovo. È possibile controllare la documentazione per il metodo compositeSubscription.add() per i dettagli sul perché. In breve, annuncerà direttamente l'abbonamento che stai tentando di aggiungere. Questa è stata una decisione deliberata (puoi leggere ulteriori informazioni a riguardo HERE).

Tornando al tuo esempio, chiamare unsubscribe() in onDestroy() dell'attività è soddisfacente e ti farà risparmiare perdite di memoria. Per quanto riguarda il tuo commento, i problemi si verificano quando chiami più volte il tuo metodo test() - Direi che il tuo problema è da un'altra parte. Forse il tuo caso d'uso non dovrebbe consentire di chiamarlo più volte, forse dovresti pulire i vecchi dati prima di usare quello appena ricevuto, ecc. Forse se hai spiegato in dettaglio che tipo di problemi hai di fronte potremmo aiutare di più. Ma per quanto riguarda lo CompositeSubscription, lo stai utilizzando e annulli l'iscrizione correttamente!

+7

ma 'onDestroy' non è garantito per essere chiamato. Significa che se onDestroy non viene richiamato per qualche motivo, si verificherà una perdita di memoria perché in questo caso anche "unsubscribe" non viene chiamato? – Storix

+0

Dato che il tuo "Osservabile" emette solo un oggetto, perché non usare un "Singolo" invece? Invece di 'onNext()', richiama un 'SingleSubscriber'' onSuccess() 'una volta, e poi è fatto (non c'è chiamata' onComplete() '). –

3

Penso che dipenda dalle vostre esigenze. Se l'attività non attenderà altre chiamate, suppongo che tu possa annullare l'iscrizione all'interno di onCompleted().

ho sempre cancellarmi a OnDestroy()

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

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

EDIT: dare un'occhiata a 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

Con l'esempio 2 devi dichiarare tutte le sottoscrizioni (variabili membro) come quelle che usi nell'attività e in Destroy annulla l'annullamento di tutte, giusto? – MarcForn

+0

@MarcForn controlla la mia modifica –

+0

Nel mio progetto sto usando CompositeSubscription, e all'interno del metodo di test aggiungo l'abbonamento a CompositeSubscription. Il problema che ho riscontrato (e questo è il motivo del post) riguarda il metodo di chiamata più volte. In questo modo mi sono reso conto che abbiamo n abbonamento (lo stesso) aggiunto all'elenco CompositeSubscription. – MarcForn

24

Non c'è bisogno di annullare l'iscrizione in onCompleted. Date un'occhiata a The Observable Contract

Quando un problemi osservabili un OnError o notifica OnComplete ai suoi osservatori, questo finisce la sottoscrizione. Gli osservatori non devono emettere una notifica di annullamento dell'iscrizione per terminare gli abbonamenti che sono terminati da Osservabili in questo modo.

D'altra parte, è necessario annullare l'iscrizione in onDestroy per evitare perdite di memoria.