[Kotlin/Android] LiveData (1)
https://developer.android.com/courses/kotlin-android-fundamentals/overview?hl=ko
Android Kotlin 기초 | 학습 과정 | Android Developers
Android Kotlin 기초 Android Kotlin 기초 교육 과정은 Google Developers 교육팀에서 만들었습니다. 이 교육 과정에서는 Android Kotlin 프로그래밍 개념에 관해 알아보고 다양한 앱을 빌드합니다. Android Kotlin 기
developer.android.com
LiveData
: 관찰 가능한 data holder class
LiveData는 어떠한 데이터든지 상관없이 Wrap할 수 있는 Wrapper이며, 감싸고 있는 기본 데이터가 변경될 때 뷰에 알리는(업데이트) 데이터 개체를 만들 수 있다.
*Observer
LiveDat class를 제대로 사용하기 위해서는 "Observer"를 설정해야 한다. Observer는 UI-Controller내에서 app의 데이터 변화를 관찰한다.
LiveData는 "수명 주기"를 인식한다. 따라서 활성 수명주기 상태에 있는 app-compenent 관찰자만 업데이트할 수 있다. 즉, '시작됨' 상태 또는 '재개됨' 상태에 있는 activity 또는 fragmet에서 업데이트 가능.
LiveData의 특징 정리
- LiveData는 관찰가능하다 : LiveData로 감싸진 데이터가 변화할 때 관찰자(Observer)는 업데이트 된다.
- LiveData는 수명 인지적이다. LiveData에 관찰자를 연결할 때, 관찰자는 UI-controller들의 수명주기와 연결된다.
따라서 LiveData는 수명주기 상태가 시작됨 또는 재개됨 일 때 관찰자를 업데이트 한다.
LiveData 소스 코드
//var word : String ->
var word = MutableLiveData<String>()
//var score :Int ->
var score = MutableLiveData<Int>()
*MutableLiveData는 읽기, 쓰기가 가능한 LiveData 타입이다. - 이 후 캡슐화에서 좀 더 자세히 다뤄보자
...
init{
word.value = ""
score.value = 0
}
...
*LiveData 값을 변경하기 위해서는 setValue를 사용해야 한다. -> 코틀린에서는 value프로퍼트를 통해 setValue()를 호출할 수 있다.
프래그먼트 내에서 LiveData - Observer 연결
프래그먼트 내에서 LiveData에 관찰자를 연결할 때, 수명주기 Owner는 Fragment View 를 사용해야 한다. - viewLifecycleOwner 사용 (정확히 모름 ㅎ)
Fragment View들은 이용자가 다른 프래그먼트로 이동할 때 파괴된다. 하지만 Fragment는 파괴되지 않는다. 다시 원래의 프래그먼트로 돌아왔을 때 Fragment view가 만들어지면서 Fragment의 수명주기와 Fragment view의 수명주기 두 개의 수명주기가 만들어진다.
이 때 파괴되지 않고 있던 Fragment의 수명주기를 그대로 사용한다면 버그를 유발할 수 있다. 따라서 Fragment View의 수명주기 Owner를 사용한다.
LiveData - Observer 소스코드
//In Fragment
//1.관찰자를 onCreateView() 에 설정한다.
override fun onCreateView() {
..
//우선 viewModel을 초기화 한 후
viewModel = viewmodelProvider(this)[ViewModel::class.java]
//2.관찰자를 인수로 viewLifeCycleOwner를 전달한다.
viewModel.word.observe(viewLifecycleOwner, Observer{ newWord -> ...}
viewModel.score.observe(viewLifecycleOwner, Observer{ newScore -> ...}
}
Observer로 전달되는 람다식은 데이터가 변화할 때 마다 "특정한 행동" 을 할 수 있게끔 한다.
예를 들어 해당 게임에서 skip버튼이나 Got 버튼을 누를 때 점수 및 스코어가 변화하게 되는데, Observer가 이런 변화를 감지하고, 그 때 마다 내가 구현한 코드가 실행되게끔 한다.
//LiveData 적용 전. setScore() , setWord()를 통해서 UI를 바꾸는 함수 구현
fun onSkip() {
viewModel.onSkip()
setScore()
setWord()
}
fun onGet() {
viewModel.onGet()
setScore()
setWord()
}
fun setScore() {
binding.scoreText.text = viewModel.score.value.toString()
}
fun setWord() {
binding.wordText.text = viewModel.word.value
}
LiveData를 Observer와 연결시키기 전에는 위와 같이 setScore()와 setWord()함수에 UI를 업데이트하는 코드를 구현하고, UI변경이 필요한 모든 부분에 해당 함수를 넣어야 하는 불편함이 있었지만, 이제는
override fun onCreateView() {
viewModel.word.observe(viewLifecycleOwner, Observer{ newWord ->
binding.wortText.text = newWord.value
}
viewModel.score.observe(viewLifecycleOwner, Observer{ newScore ->
binding.scoreText.text = newScore.value
}
}
이처럼 observer로 관찰하면서 해당 값이 변경될 때마다 ui를 업데이트하는 함수를 구현할 수 있게 되었다.
Encapsulate : LiveData 캡슐화 하기
캡슐화란? 객체의 필드 데이터(프로퍼티 또는 메소드) 에 대한 직접적인 접근을 막는 방법.
- 외부 클래스에서는 뷰모델 내의 데이터를 읽기만 하고, 직접 수정할 수는 없다.
- 내부 클래스(뷰모델 내) 에서만 private한 프로퍼티를 내부의 메서드를 통해서 수정할 수 있다.
이를 위해서는 뷰모델 내에 한 변수에 대하여 MutableLiveData 와 LiveData를 동시에 선언해줘야 한다.
- MutableLiveData는 private 변수로써 뷰모델 내에서 읽기와 쓰기 모두 가능한 변수.
- LiveData는 *Backing property로써 외부 클래스에서 읽기 용도로만 쓰는 변수.
*Backing property란? 정확한 객체가 아니라 getter로 부터 다른 것을 반환할 수 있는 프로퍼티?? 필드를 반환하는 프로퍼티?? ( ㅎㅎ 나도 정확히 모르겠따. )
캡슐화 소스코드
//val score = MutableLiveData<Int>() ->
private val _score = MutableLiveData<Int>()
val score :LiveData<Int> //Backing property
get() = _score