안드로이드

[Kotlin/Android] LiveData (1)

란서 2021. 12. 10. 22:53

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