不使用订阅的结果

时间:2018-03-27 21:22:34

标签: android android-studio rx-java2 lint android-studio-3.1

我今天已升级到Android Studio 3.1,这似乎增加了一些lint检查。其中一个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呼叫的最佳做法是什么?我应该保持Disposabledispose()完整吗?或者我应该@SuppressLint继续前进?

这似乎只影响RxJava2(io.reactivex),RxJava(rx)没有这个lint。

8 个答案:

答案 0 :(得分:87)

IDE不知道订阅在未处理时可能产生的影响,因此将其视为可能不安全。例如,您的Single可能包含网络调用,如果Activity在执行期间被放弃,则可能导致内存泄漏。

管理大量Disposable s的便捷方法是使用CompositeDisposable;只需在封闭类中创建一个新的CompositeDisposable实例变量,然后将所有的Disposable添加到CompositeDisposable(使用RxKotlin,您只需将addTo(compositeDisposable)附加到所有的Disposables)。最后,当您完成实例后,请致电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()).

答案 1 :(得分:25)

活动将被销毁的那一刻,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

答案 2 :(得分:5)

正如所建议的那样,您可以使用一些全局import datetime as dt from pandas.tseries.holiday import AbstractHolidayCalendar, Holiday, nearest_workday, \ USMartinLutherKingJr, USPresidentsDay, GoodFriday, USMemorialDay, \ USLaborDay, USThanksgivingDay class USTradingCalendar(AbstractHolidayCalendar): rules = [ Holiday('NewYearsDay', month=1, day=1, observance=nearest_workday), USMartinLutherKingJr, USPresidentsDay, GoodFriday, USMemorialDay, Holiday('USIndependenceDay', month=7, day=4, observance=nearest_workday), USLaborDay, USThanksgivingDay, Holiday('Christmas', month=12, day=25, observance=nearest_workday) ] def get_trading_close_holidays(fromyear, toyear): inst = USTradingCalendar() return inst.holidays(dt.datetime(fromyear-1, 12, 31), dt.datetime(toyear, 12, 31)) print(get_trading_close_holidays(2018,2018)) >> DatetimeIndex(['2018-01-01', '2018-01-15', '2018-02-19', '2018-03-30', '2018-05-28', '2018-07-04', '2018-09-03', '2018-11-22', '2018-12-25'], dtype='datetime64[ns]', freq=None) import datetime as dt from pandas.tseries.holiday import USFederalHolidayCalendar bday_us = CustomBusinessDay(calendar=get_trading_close_holidays(2000,2050)) d = dt.datetime(2018, 3, 31) d - bday_us >> Timestamp('2018-03-30 00:00:00') 来添加订阅操作的结果。

RxJava2Extensions库包含有用的方法,可以在CompositeDisposable完成时自动删除创建的一次性用法。请参阅subscribeAutoDispose部分。

在您的情况下,它可能看起来像这样

CompositeDisposable

答案 3 :(得分:1)

您可以通过DisposableSingleObserver进行订阅:

1500 x 296

如果需要直接处理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界面或使用其他子类。

答案 4 :(得分:1)

您可以使用Uber AutoDispose和rxjava .as

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

确保您了解基于ScopeProvider退订的时间。

答案 5 :(得分:1)

我再一次发现自己回到了如何正确处理订阅的问题,尤其是这篇帖子。一些博客和谈话声称无法调用dispose必然会导致内存泄漏,我认为这是一个过于笼统的说法。据我了解,在某些情况下,关于不存储subscribe结果的棉绒警告是没有问题的,因为:

  • 并非所有可观测对象都在Android活动的上下文中运行
  • 可观察对象可以是同步的
  • 如果可观察到的完成,则隐式调用Dispose

由于我不想抑制棉绒警告,因此我最近开始对同步可观察的情况使用以下模式:

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

无论对此是正确性的确认还是漏洞的发现,我都会对此发表评论。

答案 6 :(得分:0)

还有另一种可用的方法,那就是避免手动使用Disposables(添加和删除订阅)。

您可以定义一个 Observable ,并且该observable将从 SubjectBehaviour 接收内容(如果使用RxJava)。并将可观察到的内容传递给您的 LiveData ,它应该可以工作。根据最初的问题查看下一个示例:

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

答案 7 :(得分:-4)

如果您确定一次性处理正确,例如使用doOnSubscribe()运算符,您可以将其添加到Gradle:

android {
lintOptions {
     disable 'CheckResult'
}}