목표
- LiveData가 무엇인지 안다.
- LiveData의 setValue와 postValue의 차이점에 대해 안다.
개요
LiveData는 수명주기를 인식하는 데이터 발행자(Observable)이다.
발행자(Observable, Publisher)
리액티브 프로그래밍에서 발행자는 자신에게 붙은 구독자(subscriber)에게 데이터를 발행해주는 역할을 한다. LiveData는 수명주기를 인식하여 옵저버(observer)에게 데이터를 발행한다. 즉, LiveData는 발행자이며, 옵저버(observer)라 불리는 구독자(subscriber)을 붙일 수 있다. LiveData의 데이터가 바뀔 때 LiveData에 붙은 구독자들에게 데이터가 발행된다. 하지만, 기존 리액티브 프로그래밍과 다르게 LiveData는 자신에게 붙은 구독자들에게 언제나 데이터를 발행하는 것은 아니다.
안드로이드에서 데이터는 컴포넌트가 살아있는 동안에만 필요하다. 자 이제 수명주기를 인식한다는 것이 어떤 뜻인지 살펴보자
수명주기를 인식
안드로이드의 컴포넌트들(Activity, Fragment 등)에는 수명주기가 있는데, 이러한 수명 주기에 따라 컴포넌트가 살아있는 동안만 데이터가 필요하다. 기존 옵저버 패턴을 구현하는 다양한 발행자들은 이러한 수명주기에 대한 고려를 하지 않고 데이터를 발행해 메모리 누수가 생길 수 있었다. 이러한 단점을 보완하여 수명주기 동안만 데이터를 발행하도록 만든 Observable이 LiveData이다.
예를 들어 Activity가 있다고 해보자. Activity에서 데이터가 필요한 순간은 Activity가 살아있는 동안 뿐이다. 만약 onPause()가 호출된다면 더이상 데이터를 발행하지 않아도 되고 onDestroy()가 호출된다면 더이상 데이터가 필요 없어질 것이다.
아래의 코드를 참조하자,
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
...
}
코드1. observe 메서드
수명주기 인식 예제
LiveData는 수명주기를 인식하여 구독자에게 데이터를 발행한다 취한다. 따라서 LiveData에 구독자(observer)를 붙일 때는 LifecycleOwner인터페이스를 구현한 객체가 필요하다. Activity나 Fragment같은 LifecycleOwner 인터페이스를 구현한 클래스로 만들어진 인스턴스가 observe의 LifecycleOwner 자리에 들어갈 수 있다. 아래와 같이 붙일 수 있다.
val observer = { it: Int -> print(it) }
sampleLiveData.observe(this@MainActivity, observer)
코드2. observer 붙이기 - 변수 선언 후 붙이기
lambda식 자체를 inline시켜 다음과 같이 만들 수도 있다. 코드3 과 같이 많이 사용한다.
sampleLiveData.observe(this@MainActivity){
print(it)
}
코드3. observer 붙이기 람다로 인라인 시켜서 붙이기
발행자로서의 LiveData, MutableLivedata
LiveData는 데이터를 발행하는 발행자(Publisher)이다. 이렇다면 LiveData에 어떻게 데이터를 발행할까? LiveData는 LiveData와 MutableLiveData 두 종류가 있다. 먼저 LiveData부터 살펴보자
LiveData
LiveData는 불변 객체로 data를 setting할 수 있는 public method가 없다. 외부와 통신하여 받아오는 데이터는 보통 LiveData를 사용한다. 예를들어 Android의 SQLite를 위한 ORM Library인 Room을 이용하여 데이터를 받아올 때는 Flow를 이용하고 Flow를 asLiveData()메서드를 이용해 LiveData로 변경할 수 있다. 따라서 LiveData를 사용할 경우 직접 값을 setting 해줄 필요가 없다.
class TodoViewModel(private val todoRepository: TodoRepository) : ViewModel() {
val todoTodayWithProjectLiveData = todoRepository.todoTodayWithProjectFlow.asLiveData()
...
}
코드4. Room에서의 LiveData 예제
MutableLiveData
MutableLiveData는 가변 객체로 data를 setting할 수 있는 public method(setValue, postValue)가 있다. 만약 우리가 앱을 만들면서 데이터를 지속적으로 변경해야 한다면 해당 데이터는 MutableLiveData로 써야 한다.
MutableLiveData를 사용할 경우는 값을 넣어줄 필요가 있는데 MutableLiveData는 데이터 발행을 위해 2가지 방법을 사용할 수 있다. 바로 setValue()와 postValue()이다. 아래에서 그 둘의 차이를 알아보자
setValue()
setValue를 통해 MutableLiveData의 값을 변경할 경우 Main Thread에서 작업이 일어난다. 즉, 동기적으로 처리된다. 만약에 LiveData를 발행하는데 순서가 필요하다면 setValue를 사용해야 한다.
val sampleLiveData = MutableLiveData(1)
sampleLiveData.setValue(3)
postValue()
postValue를 통해 MutableLiveData의 값을 변경할 경우 Background Thread에서 작업이 일어난다. 즉, 비동기적으로 처리된다. LiveData 발행에 순서가 상관이 없고 Main Thread를 블록 시키지 않도록 해야 한다면 postValue를 사용해야 한다. 성능을 위해서라면 postValue를 사용하는 것이 맞지만, postValue를 사용하게 될 경우 순서가 보장이 안될 수 있으니 주의하자.
val sampleLiveData = MutableLiveData(1)
sampleLiveData.postValue(2)