[android] viewmodel에서 상태 저장 하기

sundays·2023년 3월 9일
0

viewmodel

목록 보기
2/2

viewmodel은 상태를 저장하는 곳으로 activity의 onSaveInstanceState() 의 대체제로 사용하고 있습니다.
이번 포스팅에서는 viewmodel을 사용할때의 사용방법에 대해서 살펴볼것입니다. 그리고 이전에 잠깐 다뤘던 SavedStateViewModelviewmodel의 차이점이 무엇인지에 대해서도 정리해보겠습니다

ViewModel 구현

viewmodel에서 livedata 리스트를 사용하려고 합니다. 그러기 위해서는 activity#onCreate 에 viewmodel이 observer로 viewmodel 담당이라는 것을 선언해주어야 합니다.

Activity

activity에 viewmodel을 선언할때는 여러 방법이 있습니다.

  • 2번은 NewInstanceFactory()를 생성
  • 3번은 getDefaultViewModelProviderFactory() 를 사용하지만NewInstanceFactory() 를 생성
  • 1번을 사용하면 3번처럼 사용할 수 있는 짧은 코드입니다
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은 다음과 같습니다.

ViewModel

class MyViewModel : ViewModel() {
    private var count = 0;
    
    private val _count = MutableLiveData<Int>(count)
    val countState: LiveDate<Int> = _count
    
    ....
}

어딘가에서 countState의 LiveData의 내용 변경이 일어나게 되면 위에서 선언하였던 observer()를 비동기로 실행될것입니다.

ViewModel 의 한계

그렇다고 해도 ViewModel은 완벽한 것이 아닙니다.
이전에도 포스팅한 것이지만 ViewModel의 경우에는 re-composition에는 문제가 없지만 시스템에서 시작된 프로세스 종료시에는 데이터를 유지하기 어렵습니다.
그렇다면 왜 프로세스가 사용자도 모르게 종료되어 ViewModel의 한계를 가져오게될까요?

그이유는 메모리(RAM)와 관련이있습니다.
시스템은 여유공간이 필요할때 프로세스를 임의로 종료시키고 있습니다. 그것은 프로세스의 상태에 따라 종료할 가능성을 내포하고 있습니다. (**그러나 절대로 프로세스가 백그라운드에 있어서 보이지 않는다고 반드시 종료되는것이 아닙니다!!)

그렇다면 결국 이전 viewmodel을 사용하지 않고 onSaveInstanceState() 를 사용해야 할까요?

SavedStateHandle

결론은 onSaveInstanceState() 를 사용하지 않고 viewModel에서 SavedStateHandle 을 사용하게 하면 이 문제에서 해결될 수 있습니다.
이 API를 사용하기 위해서는 확장 extension을 다운받아야합니다

implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'

Activity

선언방법은 일반 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

이 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 들을 참조하도록 합니다. 시간이 나면 해당 포스팅에 마크다운으로 하나씩 입력하겠습니다.

Reference

profile
develop life

0개의 댓글