Android按钮点击事件的Kotlin协程流程示例?

时间:2019-09-12 03:26:30

标签: android kotlin kotlin-coroutines anko

我曾经使用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本身像callbackFlowchannelFlow也在使用频道)

2 个答案:

答案 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)

到目前为止,这是最好的解决方案,没有引入Channellateinit var xxx : Flow

虽然需要定义btn属性来生成流,但它仍然比我从中迁移的Channel方法稍微复杂一点:

val btnChannel = Channel<Unit>()

// in OnClickListener
btnChannel.send(Unit)

如果有一个类似Rx的Subject或类似Channel的{​​{1}}类包含发送和接收方法,那会更好:

Flow