viewmodel은 상태를 저장하는 곳으로 activity의 onSaveInstanceState()
의 대체제로 사용하고 있습니다.
이번 포스팅에서는 viewmodel을 사용할때의 사용방법에 대해서 살펴볼것입니다. 그리고 이전에 잠깐 다뤘던 SavedStateViewModel
과 viewmodel
의 차이점이 무엇인지에 대해서도 정리해보겠습니다
viewmodel에서 livedata 리스트를 사용하려고 합니다. 그러기 위해서는 activity#onCreate
에 viewmodel이 observer로 viewmodel 담당이라는 것을 선언해주어야 합니다.
activity에 viewmodel을 선언할때는 여러 방법이 있습니다.
NewInstanceFactory()
를 생성getDefaultViewModelProviderFactory()
를 사용하지만NewInstanceFactory()
를 생성class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 1. viewmodel 선언 방법 1
val model: MyViewModel by viewModels()
// 2. viewmodel 선언 방법 2
val model = ViewModelProvider(this
, ViewModelProvider.NewInstanceFactory())
.get(MyViewModel::class.java)
// 3. viewmodel 선언 방법 3
val model = ViewModelProvider(this).get(MyViewModel::class.java)
model.countState.observe(this, Observer {
binding.counter.text = it.toString()
})
}
}
countState
를 LiveData로 수신받도록 등록하여 리스트에 변경이 생겼을때 내부 update UI(binding.counter.text = it.toString()
) 가 적용될것입니다. viewmodel은 다음과 같습니다.
class MyViewModel : ViewModel() {
private var count = 0;
private val _count = MutableLiveData<Int>(count)
val countState: LiveDate<Int> = _count
....
}
어딘가에서 countState
의 LiveData의 내용 변경이 일어나게 되면 위에서 선언하였던 observer()를 비동기로 실행될것입니다.
그렇다고 해도 ViewModel은 완벽한 것이 아닙니다.
이전에도 포스팅한 것이지만 ViewModel의 경우에는 re-composition에는 문제가 없지만 시스템에서 시작된 프로세스 종료시에는 데이터를 유지하기 어렵습니다.
그렇다면 왜 프로세스가 사용자도 모르게 종료되어 ViewModel의 한계를 가져오게될까요?
그이유는 메모리(RAM)와 관련이있습니다.
시스템은 여유공간이 필요할때 프로세스를 임의로 종료시키고 있습니다. 그것은 프로세스의 상태에 따라 종료할 가능성을 내포하고 있습니다. (**그러나 절대로 프로세스가 백그라운드에 있어서 보이지 않는다고 반드시 종료되는것이 아닙니다!!)
그렇다면 결국 이전 viewmodel을 사용하지 않고 onSaveInstanceState()
를 사용해야 할까요?
결론은 onSaveInstanceState()
를 사용하지 않고 viewModel에서 SavedStateHandle
을 사용하게 하면 이 문제에서 해결될 수 있습니다.
이 API를 사용하기 위해서는 확장 extension을 다운받아야합니다
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
선언방법은 일반 viewmodel과 다를 것은 없습니다. 다만 ViewModelProvider를 사용하고 싶을때는 SavedStateViewModelFactory
또는 defaultViewModelProviderFactory
를 사용하기도 합니다
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 1. viewmodel 선언 방법 1
val model: MyViewModel by viewModels()
// 2. viewmodel 선언 방법 2
val model = ViewModelProvider(this
, SavedStateViewModelFactory(application,this))
.get(MainViewModel::class.java)
// 3. viewmodel 선언 방법 3
val model = = ViewModelProvider(this
, defaultViewModelProviderFactory)
.get(MainViewModel::class.java)
model.countState.observe(this, Observer {
binding.counter.text = it.toString()
})
}
}
기존 Activity와 같은 기능을 제공하기 위해 observer는 동일하게 설정되었습니다.
이 viewmodel에서는 constructor에 미리 선언되어있는 SavedStateHandle
사용하여 데이터를 가져올수 있습니다. 이 viewModel은 상위의 viewmodel과 같은 로직을 가지고 있습니다.
class MyViewModel(private val handle: SavedStateHandle) : ViewModel() {
private var count = handle.get<Int>("counter") ? : 0;
set(value) {
handler.set("counter", value)
field = value
}
private val _count = MutableLiveData<Int>(count)
val countState: LiveDate<Int> = _count
...
}
데이터 타입으로 지원되고 있는 Supported types 들을 참조하도록 합니다. 시간이 나면 해당 포스팅에 마크다운으로 하나씩 입력하겠습니다.