단순 MVVM 패턴을 강의를 통해 진행한 내용 따라 써서 실습해보기
예제 1
버튼을 눌렀을 때 text의 값이 변경되도록 실습
textView의 id = tv_test
button의 id = btn_test
activity_main 코드
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<TextView
android:id="@+id/tv_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:gravity="center"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="textView" />
<Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
app:layout_constraintTop_toBottomOf="@id/tv_test" />
</androidx.constraintlayout.widget.ConstraintLayout>
1. ViewMode 생성
먼저 mainActivity의 viewModel을 생성
ViewModel()을 상속받게 생성하면 된다.
MainViewModel.kt
2.mainActivity
ViewModel 인스턴스 생성하기
2가지 방법으로 불러올 수 있다.
val viewModel = ViewModelProvider(this)[MainViewModel::class.java] //[1]
private val viewModel: MainViewModel by viewModels() //[2]
[1]
this가 사용된 경우는 Activity, Fragment 인스턴스를 의미한다.
ViewModel이 Activity나 Fragment의 수명주기와 연결되로고 하는데 도움이 된다.
[2]
by viewModels()를 사용해서 ViewModelProvider의 인스턴스를 사용하여 ViewModel을 생성하고 반환한다.
사용하기 위해서는 activity-ktx, fragment-ktx를 build.gradle에서 받아야한다.
3. lazy 사용해서 TextView, Button 초기화
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: MainViewModel by viewModels()
private val tvTest: TextView by lazy { //[1]
binding.tvTest
}
private val btnText: Button by lazy { //[2]
binding.btnTest
}
...
4. 버튼 Click Event
private fun initView() {
btnText.setOnClickListener {
// tvTest.text = "hi" //[1]
viewModel.onClickTest("hi") //[2]
}
}
[1]
버튼을 click했을 경우 hi를 즉각적으로 TextView 변경
[2]
viewModel의 onClickTest 메서드를 호출하여서 결과를 LiveData를 통해 Activity에 전달한다.
class MainViewModel : ViewModel() {
private val _event: MutableLiveData<String> = MutableLiveData()
val event: LiveData<String> get() = _event
fun onClickTest(action: String) {
val result = "result $action" //[2]
_event.value = result
}
}
▶LiveData ?
ViewModel이 View에 데이터를 줄 때 사용한다.
식별 가능한 데이터 홀더 클래스이다. 스스로 수명주기를 인식한다.
수명주기를 인식하여서 Activity나 Fragment가 활성 상태일 때만 데이터를 전달하고 비활성 상태일 때는 업데이트를 건너뛰어 리소스를 효율적으로 사용한다.
예제 2
입력받은 데이터를 Toast메시지 띄우기
et_name
et_id
et_password
btn_sign_up
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".signup.SignUpActivity">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:hint="name"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:hint="id"
app:layout_constraintTop_toBottomOf="@id/et_name" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:hint="password"
app:layout_constraintTop_toBottomOf="@id/et_id" />
<Button
android:id="@+id/btn_sign_up"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:text="회원가입"
app:layout_constraintTop_toBottomOf="@id/et_password" />
</androidx.constraintlayout.widget.ConstraintLayout>
위에 설명한 내용은 생략하고 정리를 해보면
1. SignUpViewModel - 생성
2. MainActivity
class SignUpActivity : AppCompatActivity() {
private val viewModel: SignUpViewModel by viewModels()
private val etName: EditText by lazy {
findViewById(R.id.et_name)
}
private val etId: EditText by lazy {
findViewById(R.id.et_id)
}
private val etPassword: EditText by lazy {
findViewById(R.id.et_password)
}
private val btnSignUp: Button by lazy {
findViewById(R.id.btn_sign_up)
}
...
private fun initView() {
btnSignUp.setOnClickListener {
viewModel.onClickSignUp(
etName.text.toString(),
etId.text.toString(),
etPassword.text.toString()
)
}
}
private fun initViewModel() = with(viewModel) {
event.observe(this@SignUpActivity) { event ->
when (event) {
is SignUpEvent.SignUpSuccess -> {
Toast.makeText(this@SignUpActivity,"$event",Toast.LENGTH_SHORT).show()
}
}
}
}
observe ?
LiveData의 해당 LiveData가 변경될 때 수행할 작업을 정의하는 메서드이다. LiveData의 값이 변경될 때마다 Observe가 호출되어 새 값으로 UI를 업데이트하거나 다른 작업을 수행할 수 있다.
3.ViewModel
class SignUpViewModel : ViewModel() {
private val _event: MutableLiveData<SignUpEvent> = MutableLiveData()
val event: LiveData<SignUpEvent> get() = _event
fun onClickSignUp(name: String, id: String, password: String) {
_event.value = SignUpEvent.SignUpSuccess(
name,
id,
password
)
}
}
예제1과 다르게 name, id, password를 받아와서 LiveData를 통해 전달한다.
SignUpEvent라는 이벤트를 정의하는 클래스를 따로 생성해줬다.
4.Event
sealed interface SignUpEvent {
data class SignUpSuccess(
val name: String,
val id: String,
val password: String
) : SignUpEvent
}
'Kotlin' 카테고리의 다른 글
Kotlin - 입력 예외처리 (1) | 2024.03.14 |
---|