2019년 10월 16일 수요일

ViewModel with SavedStateHandle

ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders

Saving UI state with ViewModel SavedState and Dagger

ViewModels: State persistence — SavedState

A Deep Dive into Extensible State Saving

요즘 안드로이드 개발에서는 ViewModel을 많이 사용합니다. Configuration 변경에 대한 처리를 위해 사용하기도 하겠지만 저같은 경우는 MVVM 아키텍쳐 적용에 따라 ViewModel을 사용하고 있습니다.
안드로이드에서는 보통은 view에 관련된 data를 저장하고 싶을 때 onSaveInstanceState를 통해 저장합니다. 그리고 나서 나중에 Activity나 Fragment가 생성될 때 savedInstanceState를 확인해서 필요한 값이 있으면 꺼내서 사용하죠.
그런데 MVVM을 사용하게 되면서 data를 ViewModel쪽으로 이동하게 되고 이럴경우 data를 어떻게 유지할 것인가가 이슈가 됩니다.
이에따라 구글에서는 이에 관련된 lifecycle-viewmodel-savedstate 라는 모듈을 내놓았습니다. 이 모듈에서는 어떻게 ViewModel과 Activity/Fragment 사이에서 state(data)를 유지하는지 살펴보겠습니다.

크게는 Activity/Fragment에서의 처리와 ViewModel에서의 처리 이렇게 둘로 나누어서 볼 수 있습니다.

Activity/Fragment의 경우는 기본 컨셉은 간단합니다. 종료시 ViewModel에서 제공하는 state를 저장하고 다시 시작할 때 이렇게 저장된 state를 꺼내와서 ViewModel에 전달해 줍니다.

Activity/Fragment -> SavedStateRegistryController -> SavedStateRegistry

위의 관계로 SavedStateRegistry의 performSave/performRestore 함수에서 state를 저장하고 꺼내오는 역할을 해줍니다.(코드로 보면 onCreate에서 performRestore를 호출하고, onSavedInstanceState에서 performSave를 호출해 줍니다.)
또한 Activity/Fragment는 SavedStateRegistryOwner를 구현합니다. 이때의 구현 함수인 getSavedStateRegistry()를 통해 Activity/Fragment로부터 SavedStateRegistry를 얻어서 사용할 수 있습니다.(나중에 ViewModelFactory쪽에서 사용하게 됩니다.)

ViewModel을 생성하기 위해 SavedStateViewModelFactory를 사용합니다. 아래처럼 사용하는 건 다들 아실겁니다.

private val viewModel by viewModels { SavedStateViewModelFactory(SavedStateRegistryOwner) }

짜잔~ Factory에서 SavedStateRegistryOwner를 파라메터로 받네요. Factory는 SavedStateRegistryOwner로부터 SavedStateRegistry를 얻어오고 이것으로 부터 자신이 저장했던 state를 가져와서 ViewModel에 다시 파라메터로 넘겨줍니다.

간단하게 코드를 살펴보려면 AbstractSavedStateVMFactory의 create 함수를 보면 됩니다.
SavedStateRegistry의 consumeRestoredStateForKey를 호출해서 state를 얻고, 또한 ViewModel에서 저장한 state가 저장될 수 있도록하기 위해 SavedStateRegistry의 registerSavedStateProvider를 호출해서 지금 생성하는 ViewModel의 key와 SavedStateProvider를 등록해 줍니다.

앞에서 state를 저장할 때 performSave를 호출한다고 했습니다. 이때 저장된 모든 (key, provider)에서 provider를 꺼내와서 provider.savedState()를 통해 state를 저장합니다. ViewModel에서 저장하고자 하는 state는 SavedStateHandle에 저장되게 되는데요. SavedStateProvider의 savedSate()를 호출하면 SavedStateHandle에 저장된 state를 가져오게 됩니다.

ViewModel -> SavedStateHandle -> SavedStateProvider

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...