Untitled

시작하기 전에

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

우선 본 문서에서 설명되지 않는 코드들이 있으나 SavedState와 관련된 사항만 언급하고자 하는 점 양해 부탁드립니다.

ViewMode에 Saved State 끼얹기

Saved State module for ViewModel | Android Developers

본 문서는 개념 설명을 위한 문서가 아닌 실제 구현을 위함으로 자세한 설명은 위 문서를 확인하시길 바랍니다.

시간이 없습니다! 앱 모듈에 아래 의존성을 추가하도록 합시다.

dependencies {
		...

		implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc02"

		...
}

ViewModel에 SavedStateHandle을 생성자로 넣어줍니다. 이제 ViewModel과 관련된 데이터는 별도의 외부 도움 없이 내부에서 끝나게 될 예정입니다. 그런데 SavedStateHandle는 누가 만들어 주는 걸까요?

class PhoneVerificationViewModel(
        val repository: PhoneVerificationDataSource,
        **val state: SavedStateHandle**) : ViewModel() {

    ...
}

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 P**honeVerificationViewModel(repository, handle)** as T
        }
    }
}

이제 적절한 타이밍에 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)
    }**
}