UI 관련 데이터를 저장하고 관리하는 역할
ViewModel의 이점
- 지속성
ViewModel은 ViewModel이 보유하는 상태와 ViewModel이 트리거하는 작업에서 모두 생존을 허용합니다. 캐싱을 통해 화면 회전과 같은 일반적인 구성 변경에도 데이터를 다시 가져올 필요가 없습니다. - 범위
ViewModel을 인스턴스화할 때는 ViewModelStoreOwner 인터페이스를 구현하는 객체를 전달합니다. 이는 탐색 대상, 탐색 그래프, 활동, 프래그먼트 또는 인터페이스를 구현하는 다른 유형일 수 있습니다. 그러면 ViewModel의 범위가 ViewModelStoreOwner의 생명 주기로 지정됩니다. ViewModelStoreOwner가 영구적으로 사라질 때까지 메모리에 남아 있습니다. - SavedStateHandle
사용하려면 구성 변경뿐 아니라 프로세스 재성성 전반에 걸쳐서도 데이터를 유지할 수 있습니다. 사용자가 앱을 닫았다가 나중에 열더라도 UI 상태를 그대로 유지할 수 있습니다.
ViewModel의 수명 주기
ViewModel은 액티비티 또는 프래그먼트와 다른 생명주기를 가지게 됩니다.
ViewModel이 더 이상 필요하지 않게 되면 ViewModel의 onCleared()가 호출된다.
시스템 메모리를 확보하기 위해 앱이 백그라운드로 전환되고 앱 프로세스가 종료될 때 호출된다.
finish()를 호출하거나 뒤로가기 버튼을 클릭하면 ViewModel의 onCleard()가 호출된다.
ViewModel의 장점은
- 생명 주기에 영향을 받지 않고 데이터를 유지할 수 있다.
- UI 컨트롤러와 데이터가 분리된다.
- 프래그먼트 간의 데이터 공유가 쉬워진다.
이런 문제가 발생하는 이유는 생명주기 때문이다. 화면 회전이 이루어지면 액티비티는 Destory 되었다가 다시 Create 되기 때문에 데이터가 사라지는 것이다. 이제 ViewModel을 사용해보자.
https://developer.android.com/jetpack/androidx/releases/lifecycle?hl=ko
Lifecycle | Android 개발자 | Android Developers
컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Lifecycle 수명 주기 인식 구성요소는 활동 및 프래그먼트와 같은 다른 구성요소의 수명 주기 상태 변경에 따라
developer.android.com
ViewModel 파일
package com.anushka.viewmodeldemo1
import androidx.lifecycle.ViewModel
class MainActivityViewModel : ViewModel() {
private var count = 0
fun getCurrentCount() : Int {
return count
}
fun getUpdatedCount() : Int {
return ++count
}
}
ViewModel과 AndroidViewModel을 상속받을 수 있지만 지금은 ViewModel을 상속 받았다.
(AndroidViewModel 클래스는 ViewModel 클래스를 확장한것으로 모든 기능은 동일합니다.
AndroidViewModel에 추가된 기능은 context를 인식한다는 것입니다. AndroidViewModel을 초기화할 때 application에 context를 매개변수로 전달해야 합니다.
AndroidViewModel 은 system service를 얻기 위해 context가 필요하거나 유사한 요구 사항(Toast 메시지 표시)이 있는 경우에 유용합니다.)
MainActivity파일
package com.anushka.viewmodeldemo1
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.anushka.viewmodeldemo1.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainActivityViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
viewModel = ViewModelProvider(this)[MainActivityViewModel::class.java] //ViewModel 생성코드
binding.countText.text = viewModel.getCurrentCount().toString()
binding.button.setOnClickListener {
binding.countText.text = viewModel.getUpdatedCount().toString()
}
}
}
우리가 의도한 대로 증가하고 회전 전과 동일한 카운트 값을 얻는것을 확인하였다.
이것이 기본적으로 ViewModel이 동작하는 방식입니다.
다음은 ViewModel Factory입니다.
ViewModel을 이용하다보면 repository 나 인스턴스들을 파라메터로 넘겨서 생성하는 경우가 많이 생길것입니다.
이럴때 안드로이드는 Factory 클래스를 이용해 ViewModel에 원하는 파라메터를 넣어 생성하는 방법을 제공합니다.
package com.anushka.viewmodeldemo2
import androidx.lifecycle.ViewModel
class MainActivityViewModel(startingTotal : Int) : ViewModel() {
private var total = 0
init {
total = startingTotal
}
fun getTotal():Int{
return total
}
fun setTotal(input:Int){
total += input
}
}
ViewModel에 시작 숫자를 넣어보겠습니다.
package com.anushka.viewmodeldemo2
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class MainActivityViewModelFactory(private val startingTotal : Int) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainActivityViewModel::class.java)){
return MainActivityViewModel(startingTotal) as T
}
throw IllegalAccessException("UnKnown View Model Class")
}
}
Factory 클래스를 만든 후
package com.anushka.viewmodeldemo2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.anushka.viewmodeldemo2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainActivityViewModel
private lateinit var viewModelFactory: MainActivityViewModelFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
viewModelFactory = MainActivityViewModelFactory(125)
viewModel = ViewModelProvider(this, viewModelFactory)[MainActivityViewModel::class.java]
binding.resultTextView.text = viewModel.getTotal().toString()
binding.insertButton.setOnClickListener {
viewModel.setTotal(binding.inputEditText.text.toString().toInt())
binding.inputEditText.text.clear()
binding.resultTextView.text = viewModel.getTotal().toString()
}
}
}
Factory 객체를 만든후 ViewModel에 전달했습니다.
잘 동작하는것을 확인할 수 있습니다.
참고
https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ko
ViewModel 개요 | Android 개발자 | Android Developers
ViewModel을 사용하면 수명 주기를 인식하는 방식으로 UI 데이터를 관리할 수 있습니다.
developer.android.com
https://todaycode.tistory.com/33
안드로이드 View Model(뷰 모델)을 공부해보자!
1. ViewModel 1-1. ViewModel 이란? 1-2. 탄생 배경 1-3. 사용하는 이유 2. 사용법 2-1. gradle 추가 2-2. Layout 파일 2-3. ViewModel 파일 2-4. Activity 파일 3. 주의할 점 3-1. 참조 1. ViewModel 1-1. ViewModel 이란? Clean Architectur
todaycode.tistory.com
'Android' 카테고리의 다른 글
[Android] 양방향 DataBinding (0) | 2023.02.09 |
---|---|
[Android] LiveData (0) | 2023.02.06 |
[Android] DataBinding (0) | 2023.01.29 |
무료 아이콘, BGM, 이미지 제공 사이트 (0) | 2022.12.17 |
Android - Activity 생명주기 (0) | 2022.11.23 |