액티비티를 회전하여 액티비티가 소멸되고 재생성되거나, 프로세스가 종료되어 액티비티가 유실될 때도 있습니다.
이런 경우들의 경우 기존 액티비티의 데이터를 어떻게 유지하는지 다양한 방법들을 살펴 보겠습니다.

AAC ViewModel

AAC ViewModel 이란...?

AAC의 ViewModel은 수명 주기를 고려해 관련 데이터를 저장하고 관리하도록 설계된 클래스이며 안드로이드 jetpack 의 lifecylce-extensions 라이브러리에 포함되어 제공됩니다. ViewModel 인스턴스는 액티비티의 생명주기와 연동됩니다. ViewModel 인스턴스는 액티비티 상태 변화와 무관하게 액티비티가 종료될 때까지 (예, 사용자가 백 버튼을누를 때) 메모리에 남아 있다가 액티비티가 종료되면 소멸됩니다.

사용 예제

app 수준의 gradle 에 lifecycle-extensions dependency를 추가합니다.

dependencies {
	...
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

ViewModel 은 특정 액티비티 화면과 연동되며, 모델 데이터를 화면에 보여주는 기능을 수행합니다. ViewModel 을 상속하는 ViewModel 을 생성해 줍니다.

class QuizViewModel : ViewModel() {
	// ViewModel 인스턴스가 소멸되기 전에 호출되므로 클린업할 것이 있으면 추가
   override fun onCleared() {
    	super.onCleared()
        Log.d(TAG, "ViewModel instance about to be destroyed")
    }
}

연동되는 액티비티에 ViewModel 인스턴스를 연결합니다. AAC ViewModel 클래스는 개발자가 직접 생성자 메서드로 인스턴스 생성이 불가능합니다. ViewModelProvider를 사용하여 인스턴스를 생성해야 합니다. ViewModelProvider 의 생성자로 Lifecycle 을 동일시 할 액티비티를 제공합니다.

class MainActivity : AppCompatActivity() {
	...
    override fun onCreate(savedInstanceState: Bundle?) {
    	val provider: ViewModelProvider = ViewModelProVider(this)
        val quizViewModel = provider.get(QuizViewModel::class.java)
    }
}

ViewModel 과 Activity 의 관계

액티비티는 ViewModel 을 참조하지만, ViewModel 은 액티비티를 참조하지 않습니다.
화면 회전 시에 액티비티 인스턴스는 소멸되지만, ViewModel 인스턴스는 메모리에 남습니다. 이런 상황에서 ViewModel 이 액티비티를 참조한다면 액티비티 인스턴스가 메모리에 남게되어 메모리 유실(memory leak) 이 발생할 수 있습니다.

SIS(Saved Instance State)

SIS 란...?

: 저장된 인스턴스 상태, 안드로이드 운영체제가 일시적으로 액티비티 외부에 저장하는 데이터이며, Activity.onSaveInstanceState(Bundle) 을 override 하여 SIS에 데이터를 추가할 수 있습니다.

액티비티가 Stopped 될 때 (예, 사용자가 홈 버튼을 누른 후 다른 앱을 실행할 때) 안드로이드 운영체제가 Activity.onSaveInstanceState(Bundle) 을 호출합니다. Activity.onSaveInstanceState(Bundle) 에서는 현재 액티비티의 모든 뷰들의 상태를 Bundle 데이터로 저장합니다. 저장된 데이터는 액티비티가 다시 create 될 때, Activity.onCreate(Bundle?) 에서 전달받습니다. Bundle 객체에 저장된 뷰들의 상태 데이터들을 사용해서 액티비티를 다시 생성합니다.

사용 예제

private const val KEY_INDEX = "index"

class MainActivity : AppCompatActivity() {
	...
    
    ovverride fun onSaveInstanceState(outState: Bundle){
    	super.onSaveInstanceState(outState)
        outState.putInt(KEY_INDEX, quizViewModel.currentIndex)
    }
    
    override fun onCreate(savedInstanceState: Bundle?){
    	...
        val currentIndex = savedInstanceState?.getInt(KEY_INDEX, 0) ?: 0
    }
}

activity record

액티비티(프로세스)의 소멸에도 onSaveInstanceState(Bundle)에 저장된 데이터가 존속할 수 있는 이유는 Bundle 객체가 액티비티의 activity record 로 저장되기 때문입니다.

SIS vs AAC ViewModel

SIS 에는 크거나 복잡한 객체를 저장하는 것은 피해야 합니다. 즉, UI 상태를 저장하기 위해 필요한 소량의 정보를 저장할 때는 SIS 를 사용하고, 장치의 구성 변경이 생겨 UI 에 넣는 데 필요한 많은 데이터에 빠르고 쉽게 접근하고자 메모리에 케싱할 때는 ViewModel 을 사용합니다. 프로세스가 종료된 후 액티비티 인스턴스가 다시 생성될 때는 SIS 데이터를 사용하고, 그 SIS 데이터를 사용해서 ViewModel 을 설정할 수 있습니다.


Reference

크리스틴 마시캐노, 실무에 바로 적용하는 안드로이드 프로그래밍

profile
안드로이드, flutter 개발자

0개의 댓글