[공부 기록]
이전에 ViewModel에 대하여 공부하고 프로젝트에 적용 했었다.
더 공부가 필요할 것 같았고, 함께 자주 사용되는 LiveData도 유용할 것 같아서 관련 자료를 추가로 공부했다.
안드로이드 framework에서는 사용자 제어에서 벗어나는 경우 (fragment 전환, 상태 변화 등)
UI Controller 를 제거 혹은 재생성 하게 된다.
사용중인 데이터를 서버와 연동하지 않거나 별도로 저장하지 않으면 이런 경우에 데이터를 잃게 된다.
이전에 포스팅한 onSaveINstanceState() 메소드를 활용하는 방법도 있지만,
이 방법은 작은양의 데이터를 re-load 하는데 적합하며 bitmap 이나 배열 형식의 큰 데이터에는 사용하기 어렵다.
작성 코드는 developer 문서를 참고했다.
수명 주기 인식 구성요소와 함께 Kotlin 코루틴 사용 | Android 개발자 | Android Developers
[View Model]
viewModel 상태 변화가 진행되어도 자동으로 유지된다.
다른 Activity나 Fragment 인스턴스에서도 사용 가능하다.
아래는 Activity와 ViewModel의 생명주기는 설명할 때 가장 많이 사용되는 사진이다.
Fragment도 Activity처럼 ViewModel Scope 속성에 따라서 데이터가 유지된다.
[LiveData]
LiveData 개요 | Android 개발자 | Android Developers
위의 문서로 공부했다.
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
(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> 데이터를 쉽고 빠르게 갱신할 수 있게 되었다.