El resultado de suscribirse no se utiliza.

7 minutos de lectura

avatar de usuario
Michael Dodd

Me actualicé a Android Studio 3.1 hoy, que parece haber agregado algunas comprobaciones de pelusa más. Una de estas comprobaciones de pelusa es para RxJava2 one-shot subscribe() llamadas que no están almacenadas en una variable. Por ejemplo, obtener una lista de todos los jugadores de la base de datos de mi sala:

Single.just(db)
            .subscribeOn(Schedulers.io())
            .subscribe(db -> db.playerDao().getAll());

Da como resultado un gran bloque amarillo y esta información sobre herramientas:

El resultado de subscribe no se usa

Captura de pantalla de Android Studio.  El código se resalta en amarillo con una información sobre herramientas.  Texto de información sobre herramientas: El resultado de la suscripción no se utiliza.

¿Cuál es la mejor práctica para llamadas Rx únicas como esta? ¿Debo retener el Disposable y dispose() en completo? ¿O debería simplemente @SuppressLint ¿y seguir adelante?

Esto solo parece afectar a RxJava2 (io.reactivex), Rx Java (rx) no tiene esta pelusa.

  • De sus dos soluciones, honestamente creo que @SuppressLint no es la mejor. Tal vez me equivoque, pero realmente creo que el código nunca debería alterar las advertencias y/o sugerencias del IDE.

    -Arthur Attout

    27 de marzo de 2018 a las 21:44

  • @ArthurAttout De acuerdo, actualmente me quedo con el Disposable en el ámbito de los miembros y llamando dispose() cuando se completa el sencillo, pero parece innecesariamente engorroso. Estoy interesado en ver si hay mejores maneras de hacer esto.

    -Michael Dodd

    27/03/2018 a las 21:45

  • Creo que esta advertencia de pelusa es molesta cuando la transmisión RxJava no está suscrita desde dentro de una Actividad/Fragmento/ViewModel. Tengo un Completable que puede ejecutarse de manera segura sin tener en cuenta el ciclo de vida de la actividad, pero aún así necesito deshacerme de él.

    – EM

    24 de abril de 2018 a las 23:21

  • considere RxLifecycle

    – 최봉재

    18 de abril de 2019 a las 4:32

avatar de usuario
urgentex

El IDE no sabe qué efectos potenciales puede tener su suscripción cuando no se desecha, por lo que la trata como potencialmente insegura. por ejemplo, tu Single puede contener una llamada de red, lo que podría causar una pérdida de memoria si su Activity se abandona durante su ejecución.

Una manera conveniente de administrar una gran cantidad de Disposables es usar un CompuestoDesechable; solo crea uno nuevo CompositeDisposable variable de instancia en su clase adjunta, luego agregue todos sus Desechables al CompositeDisposable (con RxKotlin puede simplemente agregar addTo(compositeDisposable) a todos sus Desechables). Finalmente, cuando haya terminado con su instancia, llame compositeDisposable.dispose().

Esto eliminará las advertencias de pelusa y garantizará que su Disposables se gestionan adecuadamente.

En este caso, el código se vería así:

CompositeDisposable compositeDisposable = new CompositeDisposable();

Disposable disposable = Single.just(db)
        .subscribeOn(Schedulers.io())
        .subscribe(db -> db.get(1)));

compositeDisposable.add(disposable); //IDE is satisfied that the Disposable is being managed. 
disposable.addTo(compositeDisposable); //Alternatively, use this RxKotlin extension function.


compositeDisposable.dispose(); //Placed wherever we'd like to dispose our Disposables (i.e. in onDestroy()).

  • me sale error de compilacion error: cannot find symbol method addTo(CompositeDisposable) con “rxjava:2.1.13”. ¿De dónde viene este método? (RxSwift o RxKotlin supongo)

    – código de aire

    8 mayo 2018 a las 17:10


  • Sí, es un método RxKotlin.

    – urgentex

    8 mayo 2018 a las 21:42

  • qué hacer en caso de fluidez

    – Caza

    3 de julio de 2018 a las 10:08

  • ¿Qué pasa si estamos haciendo esto en doOnSubscribe?

    – Shubham AgaRwal

    26 de septiembre de 2018 a las 6:41

  • No causaría una pérdida de memoria. Una vez que finaliza la llamada de red y se llama a onComplete, la recolección de elementos no utilizados se encargará del resto, a menos que haya mantenido una referencia explícita del desechable y no lo deseche.

    –Gabriel Vasconcelos

    15 de febrero de 2019 a las 14:31

avatar de usuario
Aks4125

En el momento en que se destruya la Actividad, la lista de Desechables se borrará y estaremos bien.

io.reactivex.disposables.CompositeDisposable mDisposable;

    mDisposable = new CompositeDisposable();

    mDisposable.add(
            Single.just(db)
                    .subscribeOn(Schedulers.io())
                    .subscribe(db -> db.get(1)));

    mDisposable.dispose(); // dispose wherever is required

avatar de usuario
papandreo

Puedes suscribirte con DesechableSoloObservador:

Single.just(db)
    .subscribeOn(Schedulers.io())
    .subscribe(new DisposableSingleObserver<Object>() {
            @Override
            public void onSuccess(Object obj) {
                // work with the resulting todos...
                dispose();
            }

            @Override
            public void onError(Throwable e) {
                // handle the error case...
                dispose();
            }});

En caso de que necesite disponer directamente Single objeto (por ejemplo, antes de que emita) puede implementar el método onSubscribe(Disposable d) obtener y usar el Disposable referencia.

También puedes darte cuenta SingleObserver interfaz por su cuenta o use otras clases secundarias.

avatar de usuario
Eugenio Popovich

Como se sugirió, puede usar algunos CompositeDisposable para agregar el resultado de la operación de suscripción allí.

los RxJava2Extensiones La biblioteca contiene métodos útiles para eliminar automáticamente los desechables creados de la CompositeDisposable cuando se completa. Ver subscribeAutoDispose sección.

En tu caso puede ser así

SingleConsumers.subscribeAutoDispose(
    Single.just(db)
            .subscribeOn(Schedulers.io()),
    composite,
    db -> db.playerDao().getAll())

Puedes usar Uber Eliminación automática y rxjava .as

        Single.just(db)
            .subscribeOn(Schedulers.io())
            .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this)))
            .subscribe(db -> db.playerDao().getAll());

Asegúrese de comprender cuándo cancelar la suscripción en función del ScopeProvider.

  • Esto supone que hay un proveedor de ciclo de vida disponible. Además, el método “as” está marcado como inestable, por lo que su uso generará una advertencia de Lint.

    – Aficionado

    28 de enero de 2020 a las 19:04

  • Gracias @Dabbler, de acuerdo. los .como El método fue experimental hasta RxJava 2.1.7 y en 2.2 es estable.

    – Blaffie

    29 de enero de 2020 a las 5:48


avatar de usuario
Aficionado

Una y otra vez me encuentro volviendo a la cuestión de cómo deshacerse correctamente de las suscripciones, y de esta publicación en particular. Varios blogs y charlas afirman que no llamar dispose conduce necesariamente a una fuga de memoria, lo que creo que es una declaración demasiado general. A mi entender, la advertencia de pelusa sobre no almacenar el resultado de subscribe no es un problema en algunos casos, porque:

  • No todos los observables se ejecutan en el contexto de una actividad de Android
  • El observable puede ser síncrono.
  • Dispose se llama implícitamente, siempre que el observable se complete

Como no quiero suprimir las advertencias de pelusa, recientemente comencé a usar el siguiente patrón para los casos con un observable síncrono:

var disposable: Disposable? = null

disposable = Observable
   .just(/* Whatever */)
   .anyOperator()
   .anyOtherOperator()
   .subscribe(
      { /* onSuccess */ },
      { /* onError */ },
      {
         // onComplete
         // Make lint happy. It's already disposed because the stream completed.
         disposable?.dispose()
      }
   )

Me interesaría cualquier comentario sobre esto, independientemente de si se trata de una confirmación de corrección o del descubrimiento de una laguna.

  • Esto supone que hay un proveedor de ciclo de vida disponible. Además, el método “as” está marcado como inestable, por lo que su uso generará una advertencia de Lint.

    – Aficionado

    28 de enero de 2020 a las 19:04

  • Gracias @Dabbler, de acuerdo. los .como El método fue experimental hasta RxJava 2.1.7 y en 2.2 es estable.

    – Blaffie

    29 de enero de 2020 a las 5:48


Hay otra forma disponible, que es evitar usar Desechables manualmente (agregar y eliminar suscripciones).

Puede definir un Observable y ese observable va a recibir el contenido de un AsuntoComportamiento (en caso de que uses RxJava). Y al pasar ese observable a tu Datos en tiempo real, eso debería funcionar. Mira el siguiente ejemplo basado en la pregunta inicial:

private val playerSubject: Subject<Player> = BehaviorSubject.create()

private fun getPlayer(idPlayer: String) {
        playerSubject.onNext(idPlayer)
}

private val playerSuccessful: Observable<DataResult<Player>> = playerSubject
                        .flatMap { playerId ->
                            playerRepository.getPlayer(playerId).toObservable()
                        }
                        .share()

val playerFound: LiveData<Player>
    get() = playerSuccessful
        .filterAndMapDataSuccess()
        .toLiveData()

val playerNotFound: LiveData<Unit>
    get() = playerSuccessful.filterAndMapDataFailure()
        .map { Unit }
        .toLiveData()

// These are a couple of helpful extensions

fun <T> Observable<DataResult<T>>.filterAndMapDataSuccess(): Observable<T> =
filter { it is DataResult.Success }.map { (it as DataResult.Success).data }

fun <T> Observable<DataResult<T>>.filterAndMapDataFailure(): Observable<DataResult.Failure<T>> =
filter { it is DataResult.Failure }.map { it as DataResult.Failure<T> }

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad