# 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`