我曾经使用Channel
将点击事件从Anko View类发送到Activity类,但是越来越多的Channel
函数被标记为已弃用。所以我想开始使用Flow
API。
我在下面迁移了代码:
private val btnProduceChannel = Channel<Unit>()
val btnChannel : ReceiveChannel<Unit> = btnProduceChannel
// Anko
button {
onClick {
btnProduceChannel.send(Unit)
}
}
收件人:
lateinit var btnFlow: Flow<Unit>
private set
button {
btnFlow = flow {
onClick {
emit(Unit)
}
}
}
我现在必须将流属性标记为var
,它不像以前那样优雅。这样对吗?定义属性时是否可以像Subject
一样初始化Rx Flow
?
编辑:
我拿回Channel
,然后用consumeAsFlow()
:
private val btnChannel = Channel<Unit>()
// This can be collected only once
val btnFlow = btnChannel.consumeAsFlow()
// Or add get() to make property can be collected multiple times
// But the "get()" can be easily forgotten and I don't know the performance of create flow every access
val btnFlow get() = btnChannel.consumeAsFlow()
// Send event with btnChannel
这似乎比lateinit var
更好,但是有什么方法可以完全摆脱Channel
? (尽管Flow
本身像callbackFlow
,channelFlow
也在使用频道)
答案 0 :(得分:5)
尽管我没有在项目中使用Anko,但我已经编写了此函数以与常规按钮引用一起使用,请查看它是否对您有帮助:
fun View.clicks(): Flow<Unit> = callbackFlow {
this@clicks.setOnClickListener {
this.offer(Unit)
}
awaitClose { this@clicks.setOnClickListener(null) }
}
可能的用法示例:
button.clicks()
.onEach { /*React on a click event*/ }
.launchIn(lifecycleScope)
答案 1 :(得分:0)
根据Stanislav Shamilov's answer,在某些情况下,视图和活动逻辑是分开的,他的clicks()
方法可以与lazy
结合使用。
类拥有视图:
private laitinit var btn : Button
val btnFlow by lazy { btn.clicks() }
// init btn, using Anko
button {
btn = this
}
逻辑类:
classHoldsViews
.btnFlow
.onEach { /* Handling click */ }
.launchIn(lifecycleScope)
到目前为止,这是最好的解决方案,没有引入Channel
和lateinit var xxx : Flow
。
虽然需要定义btn
属性来生成流,但它仍然比我从中迁移的Channel
方法稍微复杂一点:
val btnChannel = Channel<Unit>()
// in OnClickListener
btnChannel.send(Unit)
如果有一个类似Rx的Subject
或类似Channel
的{{1}}类包含发送和接收方法,那会更好:
Flow