Android/Kotlin

안드로이드 MVVM 이벤트 처리

easy-1 2021. 10. 18. 11:14

<개요>

ViewModel, LiveData, DataBinding 을 사용하여 이벤트를 처리하는 방법


<적용 방법>

1. Event Class 정의

- 하나의 이벤트에 대해 한번만 처리됨

open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set

    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) { // 이벤트가 이미 처리 되었다면
            null                     // null 을 반환하고
        } else {                     // 그렇지 않으면
            hasBeenHandled = true    // 이벤트가 처리되었다고 표시한 후에
            content                  // 값을 반환함
        }
    }

    // 이벤트의 처리 여부에 상관 없이 값을 반환
    fun peekContent(): T = content
}

2. EventObserver Class 정의

class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let { value ->
            onEventUnhandledContent(value)
        }
    }
}

3. activity_main.xml

- 버튼 클릭 시 viewModel 의 onEvent() 함수 호출

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="com.android.test.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/submitBtn"
            android:layout_width="match_parent"
            android:layout_height="@dimen/tab_height"
            android:onClick="@{()->viewModel.onEvent()}"
            android:text="확인"
            android:textSize="14sp"
            app:layout_constraintBottom_toBottomOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

3. MainViewModel.kt

- 발생시킬 이벤트 등록

class MainViewModel @ViewModelInject constructor() : ViewModel() {

    private val _event = MutableLiveData<Event<Boolean>>()
    val event: LiveData<Event<Boolean>>
        get() = _event

    fun onEvent() {
        _event.value = Event(true)
    }
}

4. MainActivity.kt

- DataBinding 을 통한 레이아웃 및 viewModel 등록

- viewModel 의 event 를 observe 등록함으로써 발생하는 이벤트 처리

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityTermBinding
    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.viewModel = viewModel


        // Set ObserverViewModel
        observerViewModel()
    }


    // Set Observer
    fun observerViewModel() {
        viewModel.apply {
            event.observe(this@MainActivity, EventObserver {
                val i = Intent(this@MainActivity, SecondActivity::class.java)
                startActivity(i)
            })
        }

    }
}