Activity 이동 시 데이터 저장 - 2) ViewModel

두리두두·2024년 5월 15일

Android

목록 보기
15/25

  • room으로 만든 DB CRUD를 가져다 사용하며 UIUX단 밖에서 상태관리를 하기 위해 뷰모델을 써보자!!!!
  • 요것도 투두리스트 실습을 클론코딩하다가 나온 개념이다. savedInstanceState에서 고통 받던 나에게 참 유용한 기능이구나 싶었던 뷰모델!

🧊 ViewModel이란?

  • UI 컨트롤러가 데이터에 관여하지 않도록 따로 떼어버린 것!

activity 생명주기에 따른 데이터 저장

  • 액티비티가 destoyed 될 때마다 저장하고 싶은 데이터를 savedInstanceState에 저장하고 onCreate()에서 불러와서 쓸 수 있다. 그러나 요것의 단점은

    1) 담을 수 있는 데이터가 적다.(50k 미만의 데이터 저장 권장)
    2) 담을 수 있는 데이터 형태에 제한이 있다.
    3) onCreate에서 불러와서 그려야하므로 화면 출력 시간이 걸린다

  • 그래서 UI 컨트롤러와 데이터 관리를 따로 떼어 할 수 있는게 뷰모델이다.

🧊 ViewModel의 장점

  • 뷰모델은 액티비티나 프래그먼트와 다른 생명주기를 갖는다. 액티비티에서 finished() 메소드가 호출되거나, 사용자가 직접 뒤로가기 버튼을 눌러 액티비티를 종료했을 때 onCleared() 되어 소멸된다.
  • 따라서 장점은 아래와 같이 정리할 수 있다.

    1) 액티비티나 프래그먼트보다 생명주기가 길다
    2) 데이터와 UI컨트롤러를 분리하여 관리할 수 있다.
    3) 프래그먼트 간 데이터 공유가 쉬워진다.

🧊 ViewModel 구성


(출처 : https://charlezz.com/?p=44167)

1) ViewModelProvider

  • UI단에서 프로바이더를 통해 뷰모델 인스턴스를 요청

2) ViewModelStoreOwner

  • 뷰모델 프로바이더 내부에서는 뷰모델 스토어오너를 참조하여 뷰모델스토어를 불러옴.

3) ViewModelStore

  • 만들어져있는 뷰모델 인스턴스를 가져다줌. 없으면 Factory에서 새로 생성

ViewModel을 인스턴스를 얻을 때 ViewModelProvider의 첫번째 생성자 매개변수인 ViewModelStoreOwner를 Fragment들이 속해있는 부모 Activity로 지정하자. 그러면 각 프레그먼트는 동일한 ViewModel 인스턴스를 얻게 된다. ViewModel의 생명주기는 Activity를 따르게 되고, Fragment의 생명주기는 Activity의 서브셋이므로 Fragment의 생명주기 동안에 자유롭게 데이터를 공유할 수 있게 된다.

  • 라는 설명을 봤다. ViewModelStoreOwner를 같은 것으로 하면 같은 데이터를 공유할 수 있다는 것

🧊 사용법

viewmodel class

  • 우리는 리포지토리를 사용할것이므로. 뷰모델에 리포지토리를 불러오고 CRUD 함수를 하나씩 뚫어준다.
class TodoViewModel:ViewModel() {
    val todoList: LiveData<MutableList<Todo>>
    private val todoRepository:TodoRepository = TodoRepository.get()
    init {
        todoList = todoRepository.list()
    }

    fun getOne(id : Long) = todoRepository.getTodo(id)
    fun insert(dto: Todo) = viewModelScope.launch(Dispatchers.IO){
        todoRepository.insert(dto)
    }
    fun update(dto:Todo) = viewModelScope.launch(Dispatchers.IO){
        todoRepository.update(dto)
    }
    fun delete(dto:Todo)=viewModelScope.launch(Dispatchers.IO){
        todoRepository.delete(dto)
    }
}

viewModel 객체 생성

  • 만들어둔 뷰모델로 MainActivity에서 뷰모델을 생성해보자
  • ViewModelProvider로 뷰모델 객체 생성
  • observe는 데이터 변화 감지를 위한 LivaData를 위해 사용
// 뷰모델
todoViewModel  = ViewModelProvider(this)[TodoViewModel::class.java]
	todoViewModel.todoList.observe(this){
	todoAdapter.update(it)
 }
  • 일반적으로 생성자 매개변수로 ViewModelStoreOwner와 ViewModelProvider.Factory가 필요하지만 ComponentActivity가 ViewModelStore를 구현하고 있으므로 따로 안써줘도 된다.

데이터 변화 시 사용

  • 이렇게 생성, 불러오기 하여 만들어둔 뷰모델을 데이터 변화때 사용하려면 리스너에서 변화가 필요할 때 todoViewModel.update() 등으로 사용하면 된다.
// 어답터 연결
todoAdapter.setItemCheckBoxClickListener(object :TodoAdapter.ItemCheckBoxClickListener{
      override fun onClick(view: View, position:Int, itemId:Long){
                CoroutineScope(Dispatchers.IO).launch {
                    val todo = todoViewModel.getOne(itemId)
                    todo.isChecked = !todo.isChecked
                    todoViewModel.update(todo)
                }
            }
        })
  • 뷰 모델을 각각 다른 소유자가 생성하면 이는 별개의 메모리 공간을 사용하는 다른 객체가 된다.
  • 하나의 액티비티를 소유자로 지정해 사용하면 같은 ViewModel을 공유할 수 있다. = 데이터 공유 가능
    라는 설명도 봤는데 아직은 이해가 잘 안된다 흑.. 인자가 어떤게 왜 들어가는지 정통격파할 필요가 있어보인다..
    (출처 : https://todaycode.tistory.com/33)

참고
https://youngdroidstudy.tistory.com/entry/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0%EC%9D%98-ViewModel%EA%B3%BC-LiveData

더 공부할 것들

  • 클린 아키텍처
  • LiveData
profile
야금야금 앱 개발자

0개의 댓글