---
# System prepended metadata

title: Handle One-Time Events with Kotlin's Channels
tags: [flow, channel, Android, kotlin]

---

# Handle One-Time Events with Kotlin's Channels

* 開發過程中，如果用到LiveData跟 observer，如果沒有作特殊的處理，應該會遇到旋轉螢幕導致activity recreated的時候，observer會再次觸發事件，
* 最明顯的例子應該屬顯示Toast訊息之類的

### 簡易例子
* 點擊按鈕發送Snackbar訊息
* lifecycleScope參考這裡[Use Kotlin coroutines with Architecture components](https://developer.android.com/topic/libraries/architecture/coroutines)
* 主要核心應該是將要發送的事件放進channel內，再透過一個可以暴露給外層的flow變數，使用receiveAsFlow()將channel轉換成flow，看原始碼..大概是這個flow只能會collect一次
```kotlin=
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        
        //click觸發事件
        binding.btnSendEvent.setOnClickListener {
            viewModel.sendEvent()
        }

//這裡的life cycle scope要搭配ktx dependencies使用，不需要額外控制生命週期
        lifecycleScope.launchWhenStarted {
            viewModel.eventFlow.collect { event ->
                when(event){
                    is MainViewModel.MyEvent.ErrorEvent -> {
                        Snackbar.make(binding.root,event.message,Snackbar.LENGTH_LONG ).show()
                    }
                    is MainViewModel.MyEvent.SuccessEvent ->{
                        Snackbar.make(binding.root,event.message,Snackbar.LENGTH_LONG ).show()
                    }

                }
            }
        }
    }
}

class MainViewModel : ViewModel() {

    sealed class MyEvent {
        data class ErrorEvent(val message: String) : MyEvent()
        data class SuccessEvent(val message: String): MyEvent()
    }

    private val eventChannel = Channel<MyEvent>()
    val eventFlow = eventChannel.receiveAsFlow()

    fun sendEvent() = viewModelScope.launch {
        eventChannel.send(MyEvent.ErrorEvent("here is an error"))
    }
}
```

參考資料
[Philipp Lackner's channel](https://www.youtube.com/watch?v=6v8iJDJdtMc)

###### tags: `channel` `flow` `kotlin` `Android`