在Google的官方代码实验室中,有关 advanced-coroutines-codelab 的示例中,他们将ConflatedBroadcastChannel
用作watch a variable/object change。
我在一个辅助项目中使用了相同的技术,并且在恢复监听 Activity 时,有时ConflatedBroadcastChannel
会触发其最近的值,从而导致flatMapLatest
主体的执行没有任何更改。
我认为这是在系统收集垃圾时发生的,因为我可以通过从另一个 Activity 中调用System.gc()
来重现此问题。
这是代码
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
val tvCount = findViewById<TextView>(R.id.tv_count)
viewModel.count.observe(this, Observer {
tvCount.text = it
Toast.makeText(this, "Incremented", Toast.LENGTH_LONG).show();
})
findViewById<Button>(R.id.b_inc).setOnClickListener {
viewModel.increment()
}
findViewById<Button>(R.id.b_detail).setOnClickListener {
startActivity(Intent(this, DetailActivity::class.java))
}
}
}
MainViewModel.kt
class MainViewModel : ViewModel() {
companion object {
val TAG = MainViewModel::class.java.simpleName
}
class IncrementRequest
private var tempCount = 0
private val requestChannel = ConflatedBroadcastChannel<IncrementRequest>()
val count = requestChannel
.asFlow()
.flatMapLatest {
tempCount++
Log.d(TAG, "Incrementing number to $tempCount")
flowOf("Number is $tempCount")
}
.asLiveData()
fun increment() {
requestChannel.offer(IncrementRequest())
}
}
DetailActivity.kt
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
val button = findViewById<Button>(R.id.b_gc)
val timer = object : CountDownTimer(5000, 1000) {
override fun onFinish() {
button.isEnabled = true
button.text = "CALL SYSTEM.GC() AND CLOSE ACTIVITY"
}
override fun onTick(millisUntilFinished: Long) {
button.text = "${TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished)} second(s)"
}
}
button.setOnClickListener {
System.gc()
finish()
}
timer.start()
}
}
这是完整的源代码:
CoroutinesFlowTest.zip
最佳答案
除了answer of Kiskae:
这可能不是您的情况,但是您可以尝试在接收方使用BroadcastChannel(1).asFlow().conflate
,但就我而言,这导致了一个错误,即有时未触发接收方的代码(我认为是因为conflate在单独的环境中工作协程或其他东西)。
或者,您可以使用无状态ConflatedBroadcastChannel的自定义版本(位于here)。
class StatelessBroadcastChannel<T> constructor(
private val broadcast: BroadcastChannel<T> = ConflatedBroadcastChannel()
) : BroadcastChannel<T> by broadcast {
override fun openSubscription(): ReceiveChannel<T> = broadcast
.openSubscription()
.apply { poll() }
}