본문 바로가기

Android/Basic

[Android: Jetpack] ViewModel & Lifecycle 기초(2)

 

 

앱이 강제 종료 될 경우 대비


바로 앱이 강제 종료 될 경우의 대비 방법을 알아보겠다.

여담으로, 메모리 부족 등의 이유로 시스템이 앱을 강제종료할 겨ㅇ우에는 뷰모델은 데이터를 유지할 수 없다.

 

savedStateHandle 사용

이 방법은 앞전 글에도 설명했지만, RAM에 데이터를 저장하기 때문에 많은 데이터를 저장할 수는 없다. 하지만 시스템에 의한 강제종료에도 데이터를 유지할 수 있다.

https://developer.android.com/topic/libraries/architecture/saving-states#onsaveinstancestate

이 방법은 거의 모든 코틀린 데이터 타입을 저장할 수 있다.

또, saveState에는 Key:Value 형태로 값을 저장한다.(Map이요)

 

자 그럼, 지난 글의 counter가 강제 종료 후에도 값이 유지될 수 있도록 만들어 보겠다.

 

app gradle: dependency 추가

implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1'

 

ViewModel에서 savedStateHandle을 설정

class MyViewModel(
    _counter: Int,
    private val savedStatedHandle: SavedStateHandle // 생성자에 포함된다.
): ViewModel() {
	// count 값 가져오기
	// 1. 기본적으로 savedStateHandle을 통해 가져옴
	// 2. 저장된 값이 없을 경우, 전달받은 초기값을 사용함
    var counter = savedStatedHandle.get<Int>(SAVE_STATE_KEY) ?: _counter
    
	// count 값 저장
    fun saveState() {
        savedStatedHandle.set(SAVE_STATE_KEY, counter)
    }
    
	// saveState 저장/복원에 사용할 key 값 정해준다.
    companion object{
        private const val SAVE_STATE_KEY = "counter"
    }
}

 

ViewModel 초기값으로 saveStateHandle이 추가되었으니, Factory 클래스도 수정해 준다.

Factory class 수정

@Suppress("UNCHECKED_CAST")
class MyViewModelFactory(
    private val counter: Int,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
): AbstractSavedStateViewModelFactory(owner,defaultArgs) {// 상속하는 Factory가 달라졌다.
    override fun <T : ViewModel?> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle // SavedStateHandle을 받을 수 있게 됨
    ): T {
        if(modelClass.isAssignableFrom(MyViewModel::class.java)){
            return MyViewModel(counter,handle) as T // viewModel에게 SavedStateHandle을 넘겨줌
        }
        throw IllegalArgumentException("viewModel class not found")
    }
}

 

마지막으로 액티비티 코드를 수정해준다.

Activity 코드 수정

class MainActivity : AppCompatActivity() {
    private val binding: ActivityMainBinding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        Log.d("onCreate", "onCreate")

        val factory = MyViewModelFactory(100, this) // factory에 SavedStateRegisterOwner를 전달
        val myViewModel by viewModels<MyViewModel> {factory}
        binding.textView.text = myViewModel.counter.toString()

        binding.button.setOnClickListener {
            myViewModel.counter += 1
            binding.textView.text = myViewModel.counter.toString()
            myViewModel.saveState() // 값을 증가시킬 때마다 savedStateHandle에 저장한다.
        }

    }
}

 


Uploaded by

N2T