Search
Duplicate

토막 글 - ViewMode에 Saved State 끼얹기

Tags
Engineering
Android

시작하기 전에

몇 달 전에 Facebook으로부터 끔찍한 메일을 한 통 받았습니다. 아마 이 글을 읽는 몇몇 분들 또한 Facebook Account Kit이 서비스 종료한다는 메일을 받으면서 "일이 늘어났다!!!"라는 저와 같은 생각을 하지 않으셨을까 예상합니다. 물론 우리가 시간이 없지 기술이 없는 건 아니기 때문에 Facebook에서 예고한 기간에 맞춰 대체 모듈을 작성하였고 한 가지 사소한 문제를 만나게 되었을 뿐이었습니다. 저의 소중한 저 사향 테스트폰(사실 내 폰)에서 문자 확인을 하러 앱을 이탈하기만 해도 메모리가 싹싹 증발하는 몹시 난감한 상황을 쉽게 제공해 주었습니다. 물론 안드로이드의 고질적인 문제이며 전통적인 방법으로 처리 할 수 있지만 현재의 아키텍처에서 해당 방법은 그다지 아름다운 결론으로 끝나지 않는 것을 이미 확인한 바 있었습니다. 그러다 번득 SavedState 관련 모듈이 추가되었던 것을 기억해 냈고 바로 구현에 착수하기 시작하였습니다.
우선 본 문서에서 설명되지 않는 코드들이 있으나 SavedState와 관련된 사항만 언급하고자 하는 점 양해 부탁드립니다.

ViewMode에 Saved State 끼얹기

본 문서는 개념 설명을 위한 문서가 아닌 실제 구현을 위함으로 자세한 설명은 위 문서를 확인하시길 바랍니다.
시간이 없습니다! 앱 모듈에 아래 의존성을 추가하도록 합시다.
dependencies { ... implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc02" ... }
Groovy
ViewModel에 SavedStateHandle을 생성자로 넣어줍니다. 이제 ViewModel과 관련된 데이터는 별도의 외부 도움 없이 내부에서 끝나게 될 예정입니다. 그런데 SavedStateHandle는 누가 만들어 주는 걸까요?
class PhoneVerificationViewModel( val repository: PhoneVerificationDataSource, val state: SavedStateHandle) : ViewModel() { ... }
Kotlin
PhoneVerificationViewModelFactory가 AbstractSavedStateViewModelFactory를 상속해서 구현되도록 수정해야 합니다. 기존에 사용하던 ViewModelProvider.Factory에서 추가된 점으로 create의 Parameter로 SavedStateHandle를 받아 낼 수 있고 이를 이용하여 ViewModel을 생성 할 수 있습니다.
@Module class PhoneVerificationViewModelModule { @Provides @ActivityScope fun providePhoneVerificationViewModelFactory(ㅁㅊ activity: AppCompatActivity, repository: PhoneVerificationDataSource ) = PhoneVerificationViewModelFactory(activity, repository) class PhoneVerificationViewModelFactory( val activity: AppCompatActivity, val repository: PhoneVerificationDataSource) : AbstractSavedStateViewModelFactory(activity, null) { override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T { return PhoneVerificationViewModel(repository, handle) as T } } }
Kotlin
이제 적절한 타이밍에 viewModel의 정보를 저장하는 코드를 작성하면 됩니다. 저는 구글형들이 10년 전에 지어주신 onSaveInstanceState 라는 이름이 너무너무 마음에 들기 때문에 그대로 사용하기로 했습니다.
class PhoneVerificationViewModel( val repository: PhoneVerificationDataSource, val state: SavedStateHandle) : ViewModel() { ... fun onSaveInstanceState() { state.set(COUNTRY_CODE_KEY, countryCode.value) state.set(PHONE_NUMBER_KEY, phoneNumber.value) } companion object { const val COUNTRY_CODE_KEY = "COUNTRY_CODE" const val PHONE_NUMBER_KEY = "PHONE_NUMBER" } } class PhoneVerificationActivity : GlamActivity() { @Inject lateinit var viewModelFactory: PhoneVerificationViewModelModule.PhoneVerificationViewModelFactory val viewModel: PhoneVerificationViewModel by viewModels { viewModelFactory } ... override fun onSaveInstanceState(outState: Bundle) { viewModel.onSaveInstanceState() super.onSaveInstanceState(outState) } }
Kotlin
마지막으로 ViewModel의 LiveData를 초기화시켜주는 코드를 작성하면 간단하게 구현은 끝납니다.
class PhoneVerificationViewModel( val repository: PhoneVerificationDataSource, val state: SavedStateHandle) : ViewModel() { val countryCode : MutableLiveData<String> by lazy { state.getLiveData(COUNTRY_CODE_KEY, Locale.getDefault().country) } val phoneNumber : MutableLiveData<String> by lazy { state.getLiveData(PHONE_NUMBER_KEY, "") } ... fun onSaveInstanceState() { state.set(COUNTRY_CODE_KEY, countryCode.value) state.set(PHONE_NUMBER_KEY, phoneNumber.value) } companion object { const val COUNTRY_CODE_KEY = "COUNTRY_CODE" const val PHONE_NUMBER_KEY = "PHONE_NUMBER" } ... }
Kotlin
세상 참 좋아진 것을 느낍니다.