Результат подписки не используется

Сегодня я обновился до версии Android Studio 3.1, в которую, похоже, добавлено еще несколько проверок. Одна из этих проверок lint предназначена для однократных вызовов RxJava2 subscribe(), которые не хранятся в переменной. Например, получить список всех игроков из моей базы данных комнат:

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

В результате получается большой желтый блок и эта подсказка:

Результат subscribe не используется

Screenshot of Android Studio. Code is highlighted in Yellow with a tooltip. Tooltip text: The result of subscribe is not used.

Какова лучшая практика для одноразовых вызовов Rx, как это? Должен ли я держать Disposable и dispose() по завершению? Или я должен просто @SuppressLint и двигаться дальше?

Это только влияет на RxJava2 (io.reactivex), RxJava (rx) не имеет этого пуха.

Ответ 1

IDE не знает, какие потенциальные последствия может иметь ваша подписка, когда она не удаляется, поэтому она рассматривает ее как потенциально опасную. Например, ваш Single может содержать сетевой вызов, который может вызвать утечку памяти, если ваша Activity будет отменена во время ее выполнения.

Удобный способ управления большим количеством Disposable использования - использовать CompositeDisposable; просто создайте новую переменную экземпляра CompositeDisposable в своем закрывающем классе, а затем добавьте все свои утилиты Disposables в CompositeDisposable (с помощью RxKotlin вы можете просто добавить addTo(compositeDisposable) для всех ваших одноразовых addTo(compositeDisposable)). Наконец, когда вы закончите свой экземпляр, вызовите функцию compositeDisposable.dispose().

Это избавит вас от предупреждений lint и обеспечит правильное управление вашим Disposables.

В этом случае код будет выглядеть так:

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()).

Ответ 2

Когда объект будет уничтожен, список Disposables будет очищен и будет хорош.

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

Ответ 3

Как было предложено, вы можете использовать какой-нибудь глобальный CompositeDisposable чтобы добавить туда результат операции подписки.

Библиотека RxJava2Extensions содержит полезные методы для автоматического удаления созданного одноразового использования из CompositeDisposable после его завершения. См. Раздел подписки на АвтоДиспозицию.

В вашем случае это может выглядеть так

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

Ответ 4

Вы можете подписаться на DisposableSingleObserver:

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

В случае, если вам необходимо напрямую утилизировать объект Single (например, перед его излучением), вы можете реализовать метод onSubscribe(Disposable d), чтобы получить и использовать ссылку Disposable.

Вы также можете реализовать интерфейс SingleObserver самостоятельно или использовать другие дочерние классы.

Ответ 5

Вы можете использовать Uber AutoDispose и rxjava .as

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

Убедитесь, что вы понимаете, когда отмените подписку на основе ScopeProvider.

Ответ 6

Если вы уверены, что одноразовое обращение правильно, например, с помощью doOnSubscribe(), вы можете добавить это в Gradle:

android {
lintOptions {
     disable 'CheckResult'
}}