PublishSubject blockingLast () зависает Android-приложение и не вызывает - PullRequest
0 голосов
/ 14 сентября 2018

У меня проблема с получением последнего испущенного значения от субъекта

Это мой класс, который отвечает за выдачу и наблюдение за изменениями батареи:

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

}

Когда я призываю getCurrentBatteryLevel () Он достигает blockingLast никогда не получить возвращаемое значение и зависает приложение. В чем причина и как правильно с этим справиться?

1 Ответ

0 голосов
/ 14 сентября 2018

subject.blockingLast(0) означает следующее: получить последнее значение после того, как поток завершил передачу значений, и, если он завершился, не выдав ничего, вернуть значение по умолчанию.

Это означает, что blockingLast будет ждать, пока не получит событие onComplete, потому что только тогда он сможет выяснить, что поток завершился (и выдать последнее значение).PublishSubject создает бесконечный поток , и вы никогда не вызовете batteryLevelSubject.onComplete, чтобы завершить поток вручную, и поэтому он зависает навсегда.

Вы можете легко это исправить, изменив PublishSubject на BehaviorSubject.Основное различие между ними заключается в том, что BehaviorSubject кэширует последнее полученное значение, которое затем может быть получено кем угодно.Кроме того, вам нужно изменить batteryLevelSubject.blockingLast(0) на batteryLevelSubject.value, чтобы получить последнее кэшированное значение (и оно ничего не заблокирует!).Но имейте в виду, что значение может быть нулевым при первом запуске, когда вы еще ничего не положили.Вы можете легко это исправить, создав BehaviorSubject со значением по умолчанию, например:

val subject = BehaviorSubject.createDefault(0)
...