PublishSubject blocksLast() 挂起 Android 应用程序而不调用

K.O*_*.Os 0 android kotlin rx-java rx-java2

我在从主题获取最后发出的值时遇到问题

这是我的班级,负责发射和观察电池变化:

class BatteryLevelProvider @Inject constructor(
app: App
) {

private val context: Context = app
private val receiver: PowerConnectionReceiver = PowerConnectionReceiver()

init {
initializeReceiver()
}

private fun initializeReceiver() {
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intentFilter ->
  context.registerReceiver(receiver, intentFilter)
  }
}

companion object {
 val batteryLevelSubject = PublishSubject.create<Int>()
}

fun observeBatteryLevel(): Observable<Int> = batteryLevelSubject.distinctUntilChanged()

fun getCurrentBatteryLevel(): Int {
Timber.d("getCurrentBatteryLevel: ENTERED")
val blockingLast = batteryLevelSubject.blockingLast(0)
Timber.d("getCurrentBatteryLevel: $blockingLast")
return blockingLast
}

inner class PowerConnectionReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
  val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
  val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
  val percentage= (level / scale.toFloat() * 100).toInt()
  batteryLevelSubject.onNext(percentage)
  Timber.d("Battery changed: $percentage")
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

当我调用 getCurrentBatteryLevel() 时,它到达了 blocksLast 永远不会返回值并挂起应用程序。这是什么原因以及如何正确处理?

Dmi*_*try 6

subject.blockingLast(0) 意思如下:在流完成发射值后获取最后一个值,如果它完成后没有发射任何值,则返回默认值。

这意味着blockingLast它将等到它接收到onComplete事件,因为只有这样它才能确定流已经结束(并发出最后一个值)。PublishSubject创建一个无限流,您永远不会batteryLevelSubject.onComplete手动结束流,这就是它永远挂起的原因。

您可以通过更改PublishSubject为轻松解决该问题BehaviorSubject。它们之间的主要区别在于BehaviorSubject缓存最后接收到的值,然后任何人都可以接收到该值。此外,您需要更改batteryLevelSubject.blockingLast(0)batteryLevelSubject.value获取最后一个缓存的值(它不会阻止任何内容!)。但请注意,当您尚未放置任何内容时,该值在第一次运行时可能为空。您可以通过BehaviorSubject像这样创建默认值来轻松解决这个问题:

val subject = BehaviorSubject.createDefault(0)
Run Code Online (Sandbox Code Playgroud)