안드로이드 ViewModel

이영준·2023년 5월 1일
0

📌 Jetpack

모든 안드로이드 버전과 기기에서 일관되게 작동하는 코드 작성을 도와주는 라이브러리 모음
기능에 따라 4가지로 구분된다.

📌 ViewModel

데이터를 Activity가 아닌 ViewModel에서 관리하자!!

View에서 사용되는 데이터를 쉽게 관리하도록 도와주는 역할이다.
안드로이드의 Activity 생명주기에 분리를 시켜, Activity가 재실행되어도 데이터가 소멸되지 않도록 한다. Activity가 소멸되면 ViewModel의 자원도 자연히 소멸된다.

  • 즉, 뷰 모델 객체는 activity가 finish 될 때까지 소멸되지 않으며, 화면이 rotation이 되어 activity가 재실행된다고 하더라도 뷰 모델의 데이터가 소멸되지 않는다.


참고로 Jetpack ViewModel은 MVVM 패턴에서의 ViewModel과 차이점이 있다. MVVM 패턴의 경우에는 jetpack viewmodel 및 livedata를 활용하여 뷰를 갱신하는 작업을 해야한다.

🔑 ViewModel 생성

뷰 모델을 ViewModel을 상속받는 클래스를 만들어 생성한다.

count변수를 가지고 있는 뷰 모델 하나를 만들어보자.

class MainViewModel : ViewModel() {
    //getter는 public하게, set만 private 하게
    var count = 0
        private set

    fun increaseCount(){
        count++
    }
}

액티비티에서 뷰 모델 가져오기

고전적인 방식

private val viewModel : MainViewModel by lazy{
        ViewModelProvider(this)[MainViewModel::class.java]
    }

ViewModelProvider 를 통해 현재 위와 같은 방식으로 MainViewModel을 가져올 수 있다.

이제 뷰모델을 통해 데이터에 접근해서 그 데이터를 참조하여 뷰를 변경하면

binding.increaseButton.setOnClickListener {
            viewModel.increaseCount()
            binding.countText.text = viewModel.count.toString()
        }

화면 회전 등의 이벤트가 발생하여 oncreate()가 새로 호출되도 count가 초기화되지 않고 유지된다.

🔑 앱 강제 종료시에도 데이터 보존 SavedState ViewModel


위 처럼 설정하면 백그라운드로 앱을 전환하면 자동으로 kill 해준다.
이 경우에 앱을 백그라운드로 보내면 뷰모델도 같이 사라져 데이터가 초기화된다.

그렇다면 앱이 kill되어도 데이터를 보존하려면 어떻게 해야 할까?

SavedState ViewModel
로 가능하다.

SavedState ViewModel 은 디스크에 데이터를 저장하는 방식이다.

SavedState 뷰모델은 SavedState를 지원하는 ViewModel Factory를 인자로 하여 생성한다.
이 ViewModel Factory를 따라서 만들어줘야 한다.

ViewModel

// SavedStateHandle은 프로세스가 시스템에 의해 종료되더라도 유지된다.
// SavedStateHandle 객체는 Key-Value 형태의 Map 구조
class MainViewModel(private val handle:SavedStateHandle):ViewModel() {
    //사용자의 클릭 수를 세는 변수
    var count = handle.get<Int>("count") ?: 0
        set(value){
            handle.set("count", value)
            field = value
        }

    //사용자가 클릭 했을 때 클릭수 를 증가시키는 메소드
    fun increaseCount(){
        count++
    }
}

viewModel 가져와 사용

        viewModel =  ViewModelProvider(this,
            SavedStateViewModelFactory(application, this)
        )[MainViewModel::class.java]

🔑 ViewModels()를 통한 초기화

고전적으로 뷰모델을 선언하지 않고
Fragment KTX를 활용하여 뷰모델을 선언할 수 있다.

KTX 통한 뷰 모델 초기화

    private val viewModel: MainViewModel by viewModels()
    private val viewModel by viewModels<MainViewModel>()

위의 어느 방식을 사용해도 무방하다.

🔑 Fragment에서 Activity의 viewmodel에 접근

액티비티 안의 여러 프래그먼트가 있을 때 그 여러 액티비티가 공유하는 데이터는 activity의 viewmodel에 저장하고, 프래그먼트도 각자의 viewmodel을 가지고 있으면서

공유되는 데이터를 activityViewModels() 로 가져와 처리할 수 있다.

private val activityViewModel: NewActivityViewModel by activityViewModels()

🔑 parameter을 넘겨서 뷰모델 초기화

1번 방법

2번 방법

🔑 viewmodel과 context

뷰모델은 context를 인자로 받아와서 쓰면 안된다!(activity, fragment, view 객체 등도 포함)

activity가 종료되어 자원이 소멸될 때, 뷰모델의 자원도 자연스럽게 소멸되어야 하는데, 만약 내부에서 context를 참조하고 있다면 데이터 정리가 안됨.

profile
컴퓨터와 교육 그사이 어딘가

0개의 댓글