1. ViewModel이 나오게 된 배경
ViewModel은 UI 관련 데이터를 저장하고 관리해주는 역할을 합니다.
앱을 만들 때 화면을 세로에서 가로로 회전하면 화면에 있던 데이터가 날라가는 경우가 있습니다. 화면이 전환될 때는 단지 방향만 바뀌는 것이 아니라 액티비티가 destroy 되었다가 다시 create 되는데, 이때 데이터가 날라가기 때문입니다.
이때 데이터를 보존하기 위해 savedInstanceState를 사용할 수 있습니다. 그러나 구글에서는 여기에 50k 미만의 데이터만 담도록 권장하고 있으며, 담을 수 있는 데이터의 형태도 제한되어 있습니다. 또한 onCreate() 메서드에서 작업을 처리해야 하기 때문에 UI 컨트롤러가 해야 할 일이 늘어나면서 화면을 띄우는 데 시간이 오래 걸립니다.
이를 해결하기 위해 나온 것이 바로 ViewModel입니다.
2. 개요
뷰모델은 액티비티 또는 프래그먼트와 다른 생명주기를 갖습니다. 액티비티나 프래그먼트가 finish() 메서드를 통해 종료되었을 때 뷰모델은 onCleared() 메서드를 통해 비로소 소멸이 됩니다. 즉, 액티비티나 프래그먼트보다 생명주기가 더 깁니다.
따라서 뷰모델은 다음의 이점이 있습니다.
- 생명주기의 영향을 받지 않고 데이터를 유지할 수 있다.
- UI 컨트롤러와 데이터가 분리된다. 이를 통해 클린 아키텍쳐를 달성할 수 있다.
- 프래그먼트 간의 데이터 공유가 쉬워진다.
3. 사용법
1) 빌드 종속 항목 추가
build.gradle(app) 파일에 아래 코드를 추가합니다.
이때 버전은 최신이 아닐 수 있으므로 공식 문서에서 확인한다. (https://developer.android.com/jetpack/androidx/releases/lifecycle?hl=ko#declaring_dependencies)
def lifecycle_version = "2.4.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
2) ViewModel 생성
class TapViewModel : ViewModel() {
// MutableLiveData객체 생성
var _score = MutableLiveData<Int>()
// MutableLiveData를 ViewModel의 LiveData에 넣는다.
val score : LiveData<Int>
get() = _score
init {
_score.value= 0
}
fun increase() {
_score.value= _score.value?.plus(1)
}
}
mutableLiveData 객체를 생성합니다. 이는 변경이 가능한 LiveData입니다.
LiveData는 변경이 안 됩니다. 따라서 데이터를 수정할 때에는 mutableLiveData를 사용하고, 값을 가져올 때에도 이 값을 가져옵니다.
3) 액티비티 파일 생성
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMain2Binding
lateinit var tapViewModel: TapViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
tapViewModel = ViewModelProvider(this).get(TapViewModel::class.java)
binding.score= tapViewModel
val scoreObserver =Observer<Int>{it ->
binding.textScore.text= it.toString()
}
tapViewModel.score.observe(this, scoreObserver)
}
}
이때 앞서 배운 databinding을 사용합니다.
또한 observe를 사용하면 데이터가 갱신될 때마다 이를 viewModel이 캐치해서 특정 동작을 수행하도록 설정할 수 있습니다. 이 경우 데이터가 변경되면 이를 바로바로 textView에 표시하도록 설정했습니다.
4) 레이아웃 파일 작성
<?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="score"
type="com.example.tmp.TapViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:id="@+id/textScore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="현재 점수는 : "
android:textSize="40sp"
android:layout_marginBottom="30dp"
/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnIncrease"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Increase"
android:textSize="20sp"
android:textColor="@color/white"
android:background="@color/black"
android:onClick="@{() -> score.increase()}"
android:padding="10dp"/>
</LinearLayout>
</layout>
btnIncrease 라는 버튼에 onClick을 통해 클릭 이벤트를 설정합니다.
이 경우 score 변수의 값을 증가하도록 설정합니다.
4. 시연 영상
'Android > 공부' 카테고리의 다른 글
AnimationDrawable 사용해서 애니메이션 만들기 (0) | 2021.12.07 |
---|---|
Databinding에 대해서 (0) | 2021.12.06 |
커스텀 보틈시트(BottomSheet) 만들기 (0) | 2021.12.04 |
커스텀 스낵바, 커스텀 토스트 만들기 (0) | 2021.12.03 |
안드로이드 스크린샷 감지 (3) | 2021.12.02 |