Android ViewModel과 LiveData 공부기록

[공부 기록]

 

이전에 ViewModel에 대하여 공부하고 프로젝트에 적용 했었다.

더 공부가 필요할 것 같았고, 함께 자주 사용되는 LiveData도 유용할 것 같아서 관련 자료를 추가로 공부했다.

 

안드로이드 framework에서는 사용자 제어에서 벗어나는 경우 (fragment 전환, 상태 변화 등)

UI Controller 를 제거 혹은 재생성 하게 된다.

사용중인 데이터를 서버와 연동하지 않거나 별도로 저장하지 않으면 이런 경우에 데이터를 잃게 된다.

이전에 포스팅한 onSaveINstanceState() 메소드를 활용하는 방법도 있지만,

이 방법은 작은양의 데이터를 re-load 하는데 적합하며 bitmap 이나 배열 형식의 큰 데이터에는 사용하기 어렵다.

 

작성 코드는 developer 문서를 참고했다.

수명 주기 인식 구성요소와 함께 Kotlin 코루틴 사용  |  Android 개발자  |  Android Developers

 

수명 주기 인식 구성요소와 함께 Kotlin 코루틴 사용  |  Android 개발자  |  Android Developers

수명 주기 인식 구성요소와 함께 Kotlin 코루틴 사용 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Kotlin 코루틴은 비동기 코드를 작성할 수 있게 하는 API를

developer.android.com

 

[View Model]

 

viewModel 상태 변화가 진행되어도 자동으로 유지된다.

다른 Activity나 Fragment 인스턴스에서도 사용 가능하다.

아래는 Activity와 ViewModel의 생명주기는 설명할 때 가장 많이 사용되는 사진이다.

Fragment도 Activity처럼 ViewModel Scope 속성에 따라서 데이터가 유지된다. 

viewmodel의 lifecycle

 

[LiveData]

 

LiveData 개요  |  Android 개발자  |  Android Developers

 

LiveData 개요  |  Android 개발자  |  Android Developers

LiveData를 사용하여 수명 주기를 인식하는 방식으로 데이터를 처리합니다.

developer.android.com

 

위의 문서로 공부했다.

LiveDAta는 관찰 가능한 데이터 홀더 클래스이다.

다른 일반 클래스와 다른 점은 앱 구성요소의 수명 주기를 인식하고 고려한다.

활동 수명 주기 상태에 있는 구성 요소만을 관찰(Observer)하여 데이터를 업데이트한다.

 

[Observer] : (관찰자) 수명 주기가 STARTED or RESUMED 상태면 활성 상태로 간주

                      비활성 관찰자는 변경사항을 확인하지 않음

 

[LiveData 사용 이점]

 

1. UI와 데이터 상태 일치 보장 : 사용자가 보는 UI가 실시간 데이터 변화에 따라 업데이트

2. 메모리 누수 없음 *** : 연결된 수명 주기가 끝나면 자동으로 삭제 (매우 중요)

3. 비정상 종료 없음 : state가 백 스택에 있는 등 수명 주기가 비활성화 상태면 이벤트 처리 안함

4. 리소스 공유 : LiveData 객체를 확장하여 시스ㅔㅁ 서비스를 래핑할 수 있음

 

1,2,3번은 너무 중요한 이점이고 4번은 LiveData 확장에 대한 메뉴얼이 있지만

사용할 일이 없을 것 같아서 일단은 생략하고 공부했다.

 

[LiveData 사용]

 

1. LiveData 인스턴스 생성 ( ViewModel 클래스 내부에서 일어남)

2. Observer 객체 생성 (데이터 변경 작업 제어 역할)

3. observe() 메서드로 LIveData 객체에 Observer 객체를 연결

 

 

[프로젝트에 적용하기 위해 실습 진행]

 

우선 viewModel 클래스를 만든다.

 

class ToDoMainViewModel : ViewModel(){
    var todoLiveData = MutableLiveData<ArrayList<Todo>>()
    //데이터를 여기서 관리함 - 뷰모델은 액티비티가 종료될때 종료
    private var todoData = ArrayList<Todo>()
}

 

일정 관리를 위한 ViewModel이므로 ToDoMainViewModel로 선언했다.

그 후에 todoLiveData를 MutableLiveData로 선언 해준다.

MutableLiveData  |  Android Developers

 

MutableLiveData  |  Android Developers

androidx.car.app.managers

developer.android.com

 

(Mutable : 변할 수 있는 )LiveData는 객체에 저장된 값을 수정하기 위해 사용된다.

이후에 todoData를 선언했는데 Todo data class의 List로 ViewModel에서 관리할 데이터이다.

 

<Todo data class>

data class Todo(
    val text : String,
    var isDone : Boolean,
)

 

이제 ToDoMainViewModel 내부에 데이터를 추가, 삭제, 수정하기 위한 함수들을 선언한다.

 

fun addData(text:String){
    todoData.add(Todo(text, false))
    todoLiveData.value = todoData
}

fun delData(todo: Todo){
    todoData.remove(todo)
    todoLiveData.value = todoData
}
fun changeData(todo:Todo){
    todo.isDone = !todo.isDone
    todoLiveData.value = todoData
}

 

외부에서 이 함수들을 통해서 데이터를 관리하게 된다.

 

이제 MainActivity에서 ViewModel을 선언한다.

 

private val viewModel : ToDoMainViewModel by viewModels()

 

이 한 줄로 간단하게 선언이 가능하다.

 

binding.addButton.setOnClickListener {
    viewModel.addData(binding.editText.text.toString())
}

 

앞에서 선언한 함수로 쉽게 데이터를 관리할 수 있다.

하지만 LiveData로 선언해주었으므로 Observe를 활용해야 한다.

 

<updateUI 함수>

//관찰 UI 업데이트
private fun updateUI(){
    viewModel.todoLiveData.observe(this, Observer {
        (binding.todoRecycler.adapter as ToDoAdapter).setData(it)
    })
}

 

onCreate() 에서 updateUI()를 실행시킨다.

데이터에 대한 관찰을 하므로 반드시 viewModel이 선언된 후에 선언 해야한다.

observe함수는 data의 변경이 감지되면 만들어둔 Recycler View의 setData 함수를 실행시킨다.

 

<RecyclerView.setData>

 

//데이터 변경 시 해당 메서드 실행
@SuppressLint("NotifyDataSetChanged")
fun setData(newData:ArrayList<Todo>){
    dataSet = newData
    notifyDataSetChanged()
}

 

데이터가 변경되면 observe()에서 이를 감지하고 RecyclerView 내부의 setData 함수를 실행한다.

setData함수가 RecyclerView 내부의 data를 변경하고 notifyDataSetChanged()로 해당 변경을 알린다.

뷰 모델에서 변경 - observe() 감지 - 리싸이클러 뷰 데이터 갱신 순서로 실행되는 것이다.

 

이제 LiveData+ViewModel을 사용해서 대량의 ArrayLIst<Todo> 데이터를 쉽고 빠르게 갱신할 수 있게 되었다.