# (Android) MVVM架構如何從viewModel發送event給view > 方法1. 單純使用LiveData (不好) > 問題1. View生命週期重置時,會收到之前的event ```kotlin= class DemoViewModel { val event = MutableLiveData<String>() fun sendEvent(){ event.postValue("new event post") } } class DemoFragment : Fragment() { private val viewModel = DemoViewModel() fun main(){ viewModel.event.observe(viewLifecycleOwner, Observer { println("received event : $it") }) } } ``` --- > 方法2. 用變數判斷有無處理過(還是不好) > 問題1. 忘記重置handled變數 > 問題2. View不應該處理邏輯 ```kotlin= class DemoViewModel { var handled = false val event = MutableLiveData<String>() //... } class DemoFragment : Fragment() { private val viewModel = DemoViewModel() fun main(){ viewModel.event.observe(viewLifecycleOwner, Observer { if(!viewModel.handled) println("received event : $it") viewModel.handled = true }) } } ``` --- > 方法3. 使用SingleLiveEvent(尚可) > 使用Hack作法讓LiveData只發送一次更新 > Google已放棄此種做法 https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java --- > 方法4. 封裝Event(Google推薦) > 對Event取值時一併處理Handled狀態 ```kotlin /** * Used as a wrapper for data that is exposed via a LiveData that represents an event. */ open class Event<out T>(private val content: T) { var hasBeenHandled = false private set // Allow external read but not write /** * Returns the content and prevents its use again. */ fun getContentIfNotHandled(): T? { return if (hasBeenHandled) { null } else { hasBeenHandled = true content } } /** * Returns the content, even if it's already been handled. */ fun peekContent(): T = content } ``` ```kotlin= class DemoViewModel { val event = MutableLiveData<Event<String>>() //... } class DemoFragment : Fragment() { private val viewModel = DemoViewModel() fun main(){ viewModel.event.observe(viewLifecycleOwner, Observer { it.getContentIfNotHandled()?.let { data -> println("received event : $data") } }) } } ``` 仔細看,View還是處理了邏輯 View在判斷getContentIfNotHandled()是否為空值,只是換了個寫法 正當我心想Google終究還是違反了原則 發現Google還搭配了一個EventObserver ```kotlin= /** * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has * already been handled. * * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled. */ class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> { override fun onChanged(event: Event<T>?) { event?.getContentIfNotHandled()?.let { value -> onEventUnhandledContent(value) } } } ``` 改用EventObserver去觀察Event的話,View的邏輯就被抽離了 最後View程式碼的如下 ```kotlin= class DemoFragment : Fragment() { private val viewModel = DemoViewModel() fun main(){ viewModel.event.observe(viewLifecycleOwner, EventObserver { println("received event : $it") }) } } ```