我今天已升级到Android Studio 3.1,这似乎增加了一些lint检查。其中一个lint检查是针对未存储在变量中的一次性RxJava2 subscribe()
调用。例如,从我的房间数据库中获取所有玩家的列表:
Single.just(db)
.subscribeOn(Schedulers.io())
.subscribe(db -> db.playerDao().getAll());
导致一个大的黄色块和这个工具提示:
未使用
subscribe
的结果
这样的一次性Rx呼叫的最佳做法是什么?我应该保持Disposable
和dispose()
完整吗?或者我应该@SuppressLint
继续前进?
这似乎只影响RxJava2(io.reactivex
),RxJava(rx
)没有这个lint。
答案 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
结果的棉绒警告是没有问题的,因为:
由于我不想抑制棉绒警告,因此我最近开始对同步可观察的情况使用以下模式:
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'
}}