[Android] ViewModel은 어떻게 값을 유지할까?

신민준·2026년 1월 7일

안드로이드

목록 보기
5/6

들어가며

ComponentActivity 코드

@Suppress("deprecation")
final override fun onRetainNonConfigurationInstance(): Any? {
    // Maintain backward compatibility.
    val custom = onRetainCustomNonConfigurationInstance()
    var viewModelStore = _viewModelStore
    if (viewModelStore == null) {
        // No one called getViewModelStore(), so see if there was an existing
        // ViewModelStore from our last NonConfigurationInstance
        val nc = lastNonConfigurationInstance as NonConfigurationInstances?
        if (nc != null) {
            viewModelStore = nc.viewModelStore
        }
    }
    if (viewModelStore == null && custom == null) {
        return null
    }
    // 'NonConfigurationInstances'라는 내부 전용 보관 상자 생성
    val nci = NonConfigurationInstances()
    nci.custom = custom
    nci.viewModelStore = viewModelStore // 여기에 현재의 ViewModel들이 담긴 바구니를 넣음
    return nci // 이 상자를 안드로이드 시스템(OS)에 맡김
}

onPause() -> onStop() -> [이 시점에 호출] -> onDestroy()

ActivityThread.java 
void performDestroyActivity(ActivityClientRecord r, boolean finishing, boolean getNonConfigInstance, String reason) {
    Class < ? extends Activity > activityClass;
    if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
    activityClass = r.activity.getClass();
    if (finishing) {
        r.activity.mFinished = true;
    }
    performPauseActivityIfNeeded(r, "destroy");
    if (!r.stopped) {
        callActivityOnStop(r, false /* saveState */, "destroy");
    }
    if (getNonConfigInstance) {
        try {
            r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException ("Unable to retain activity "
                    + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
            }
        }
    }
    ...
}

이후 액티비티 재생성시 다음 코드로부터 ViewModelStore를 가져옴

ComponentActivity.kt
override val viewModelStore: ViewModelStore
    /**
     * Returns the [ViewModelStore] associated with this activity
     *
     * Overriding this method is no longer supported and this method will be made `final` in a
     * future version of ComponentActivity.
     *
     * @return a [ViewModelStore]
     * @throws IllegalStateException if called before the Activity is attached to the
     *   Application instance i.e., before onCreate()
     */
    get() {
        checkNotNull(application) {
            ("Your activity is not yet attached to the " +
                "Application instance. You can't request ViewModel before onCreate call.")
        }
        ensureViewModelStore()
        return _viewModelStore!!
    }

private fun ensureViewModelStore() {
    if (_viewModelStore == null) {
        val nc = lastNonConfigurationInstance as NonConfigurationInstances?
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            _viewModelStore = nc.viewModelStore
        }
        if (_viewModelStore == null) {
            _viewModelStore = ViewModelStore()
        }
    }
}

lastNonConfigurationInstance로 파괴되기 전에 저장한 기존의 ViewModelStore를 가지고 있는NonConfigurationInstances를 가져와서 값으로 설정한다.

정리는 완전히 죽을 때만 하고 이것은 ComponentActivity의 init에서 설정

init {
    ...
    @Suppress("LeakingThis")
    lifecycle.addObserver(
        LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                contextAwareHelper.clearAvailableContext()
                // And clear the ViewModelStore
                if (!isChangingConfigurations) {
                    viewModelStore.clear() <- 여기
                }
                reportFullyDrawnExecutor.activityDestroyed()
            }
        }
    )
    ...
}

마무리

profile
안드로이드 외길

0개의 댓글