본문 바로가기

Android/Tech

Android ViewModel 의 onCleared() 는 언제 호출되는가?

Unsplash, Erik Karits.

ViewModel

ViewModel 은 이제는 안드로이드 프로그래밍에 있어서 필수 불가결한 존재가 되었습니다. 특히 MVVM, MVI, MVW 등, 관심사의 철저한 분리가 요구되는 아키텍처에는 꼭 필요합니다. 특정 아키텍처를 적용하지 않더라도, View 가 표시할 상태나 데이터를 위해 ViewModel 이 필요하기도 하고요.

 

Rx라이브러리를 이용하거나 ViewModel 내에서 특정 리소스를 Observing 하는 경우에는 메모리 릭에 대한 리스크를 관리하기 위해 ViewModel 의 onCleared() 에서 관련 작업 또는 리소스들을 해제해주어야 합니다. 이는 다소 제네럴한 지식이고요.

 

문득, onCleared() 가 언제, 또 어떻게 호출되는지 궁금해졌습니다.

 


내부 동작 방식

ViewModel 의 onCleared() 는 그 명칭을 보아 호출의 주체가 되지 않는 함수로 보입니다즉, 개발자에 의해 직접 호출되는 것이 아닌, 내부적으로 이미 해당 메서드를 호출하고 있는 소스가 존재한다는 것입니다.

 

    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }

    @MainThread
    final void clear() {
        mCleared = true;
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    closeWithRuntimeException(value);
                }
            }
        }
        if (mCloseables != null) {
            synchronized (mCloseables) {
                for (Closeable closeable : mCloseables) {
                    closeWithRuntimeException(closeable);
                }
            }
        }
        onCleared();
    }

 

onCleared() 메서드는 clear() 메서드의 마지막에 호출됩니다. clear() 메서드는 ViewModelStore 클래스의 clear() 메서드에서 호출됩니다. 

 

/**
 * Clears internal storage and notifies `ViewModel`s that they are no longer used.
 */
fun clear() {
    for (vm in map.values) {
        vm.clear()
    }
    map.clear()
}

 

다소 간단한 명세의 clear() 메서드는 ComponentActivity 에서, 발생한 Lifecycle Event 가 ON_DESTROY 인 경우 호출됩니다.

 

getLifecycle().addObserver(new LifecycleEventObserver() {
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            // Clear out the available context
            mContextAwareHelper.clearAvailableContext();
            // And clear the ViewModelStore
            if (!isChangingConfigurations()) {
                getViewModelStore().clear();
            }
            mReportFullyDrawnExecutor.activityDestroyed();
        }
    }
});

 

ComponentActivity 의 기본 생성자에 정의된 코드이며, Lifecycle 을 트래킹하는 익명 클래스를 통해 통지하는 방식으로 구현되어 있습니다. Lifecycle Event 는 ON_DESTROY 이지만 구성 변경이 아닌 경우에만 동작합니다. 즉, ViewModel 은 Activity 의 onDestroy 에 해제됩니다.

 


포스팅 동기

"왜 UI 데이터의 보존과 핸들링을 위해 ViewModel 을 사용해야 하나요?"

 

라는 질문을 보게되었고, 쉽게 대답할 수 있는 질문이라고 생각했습니다. 그래서 답변을 생각해보았습니다.

 

"관심사의 분리를 위해 Activity / Fragment 는 UI 표시를 위한 역할만을 담당하고, 그에 대한 데이터 핸들링은 Activity 나 Fragment 보다 생명주기가 조금 더 긴 ViewModel 에서 담당하는 것이 UI 데이터 처리의 안정적인 방식이기 때문입니다."

 

제가 참여하고 있는 네이버 부스트캠프의 동료 캠퍼들도 비슷하게 답변을 줬는데요.

그런데 문득, OnDestroy 는 Activity 의 해제를 의미하는데, 그렇다면 ViewModel 을 해제해주는 건 누가 담당하는 걸까? 라는 의문이 들었습니다.

 

이러한 동기로 이에 관해 정리하고 싶었고, 정리한 결과, 조금은 다르게 답변해야 함을 알 수 있었습니다.

 

"관심사의 분리를 위해 Activity / Fragment 는 UI 표시를 위한 역할만을 담당하고, 그에 대한 데이터 핸들링은 런타임 중 안드로이드 구성 변경 등에 의해 해제되지 않는 ViewModel 에서 담당하는 것이 UI 데이터 처리의 안정적인 방식이기 때문입니다."

 


 

Android 공식 문서, ViewModel 개요.

 

ViewModel 과 관련된 글에 꼭 등장하는 이미지입니다. 이 이미지가 설명하려 하는 바는 ViewModel 은 onCleared() 에 메모리에서 해제된다 인 것 같은데, 이게 하필 Activity Lifecycle 바로 옆에 수직으로 그려져 있어서 '아, ViewModel 은 Activity 보다 조금 더 긴 Lifecycle 을 가지는구나!' 라고 착각하게 된 것 같습니다. 

 

즉, ViewModel 은 Activity 보다 더 긴 Lifecycle 을 가지는 게 아닌, 구성 변경에 의해 해제되지 않는 것일 뿐, Activity 의 onDestory 에 함께 해제된다. 입니다.