Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin coroutine flow example for Android button click event?

I used to use Channel to send out click event from Anko View class to Activity class, however more and more Channel functions are marked as deprecated. So I wanted to start using Flow apis.

I migrated code below:

private val btnProduceChannel = Channel<Unit>()
val btnChannel : ReceiveChannel<Unit> = btnProduceChannel 

// Anko
button {
    onClick {
        btnProduceChannel.send(Unit)
    }
}

to:

lateinit var btnFlow: Flow<Unit>
    private set

button {
    btnFlow = flow { 
       onClick { 
            emit(Unit) 
       }
    }
}

I have to mark flow properties as var now which is not so elegant as before. Is this way right? Can I init a Rx Subject like Flow when defining the property?


Edit:

I brought Channel back, then used 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

This seems better than lateinit var one, but any way to get rid of Channel completely? (Though Flow itself like callbackFlow, channelFlow are using channel)

like image 252
Zouyiu Ng Avatar asked Sep 12 '19 03:09

Zouyiu Ng


1 Answers

Although I don't use Anko in my project, I've written this function to use with regular button references, see if it helps you:

fun View.clicks(): Flow<Unit> = callbackFlow {
    setOnClickListener {
        offer(Unit)
    }
    awaitClose { setOnClickListener(null) }
}

An example of possible usage is:

button.clicks()
   .onEach { /*React on a click event*/ }
   .launchIn(lifecycleScope)

UPDATE

As @Micer mentioned in the comments to the original answer, the method Channel#offer has become deprecated in the favour of Channel#trySend method.

The updated version:

fun View.clicks() = callbackFlow<Unit> {
    setOnClickListener {
        trySend(Unit)
    }
    awaitClose { setOnClickListener(null)}
}
like image 161
Stanislav Shamilov Avatar answered Nov 16 '22 09:11

Stanislav Shamilov