1. LiveData란?
LiveData는 Data의 변경을 관찰할 수 있는 Data Holder 클래스이다.
일반적인 Observable과는 다르게 LiveData는 안드로이드 생명주기(LifeCycle)을 알고 있다.
즉, 액티비티, 프래그먼트, 서비스 등과 같은 안드로이드 컴포넌트의 생명주기(LifeCycle)를 인식하며 그에따라 LiveData는 활성상태(active)일 때만 데이터를 업데이트한다.
여기서 활성상태란 STARTED 또는 RESUMED를 의미한다.
또한 LiveData 객체는 Observer 객체와 함께 사용된다. LiveData가 가지고 있는 데이터에 어떠한 변화가 일어날 경우, LiveData는 등록된 Observer 객체에 변화를 알려주고, Observer의 onChanged() 메소드가 실행되게 된다.
2. LiveData가 어떻게 생명주기를 알아요?
바로 LifeCycleOwner이라는 녀석이 안드로이드 생명주기 (Android LifeCycle)를 알고 있는 클래스라 보면 된다.
메소드가 오직 getLifeCycle() 밖에 없는 단일 메소드 인터페이스 클래스이며, Activity나 Fragment에서 이를 상속하고 있다.
한 마디로 LiveData의 Observer 메소드의 LifeCycleOwner를 Activity나 Fragment를 변수로써 사용한다면 각 화면 별 생명주기에 따라 LiveData는 자신의 임무를 수행한다.
3. 장점이 뭐죠?
Data와 UI간 동기화
LiveData는 Observer 패턴을 따른다. 그에따라 LiveData는 안드로이드 생명주기에 데이터 변경이 일어날 때마다 Observer 객체에 알려준다. 그리고 이 Observer 객체를 사용하면 데이터의 변화가 일어나는 곳마다 매번 UI를 업데이트하는 코드를 작성할 필요 없이 통합적이고 확실하게 데이터의 상태와 UI를 일치시킬 수 있다.
메모리 누수(Memory Leak)가 없다.
Observer 객체는 안드로이드 생명주기 객체와 결합되어 있기 때문에 컴포넌트가 Destroy 될 경우 메모리 상에서 스스로 해제한다.
Stop 상태의 액티비티와 Crash가 발생하지 않는다.
액티비티가 Back Stack에 있는 것처럼 Observer의 생명주기가 Inactive(비활성화)일 경우, Observer는 LiveData의 어떤 이벤트도 수신하지 않는다.
생명주기에 대한 추가적인 handling을 하지 않아도 된다.
LiveData가 안드로이드 생명주기에 따른 Observing을 자동으로 관리를 해주기 때문에 UI 컴포넌트는 그저 관련 있는 데이터를 "관찰"하기만 하면 된다.
항상 최신 데이터를 유지한다.
화면 구성이 변경되어도 데이터를 유지한다.
예를 들어, 디바이스를 회전하여 세로에서 가로로 화면에 변경될 경우에도 LiveData는 회전하기 전의 최신 상태를 즉시 받아온다.
자원(Resource)를 공유할 수 있다.
LiveData를 상속하여 자신만의 LiveData클래스를 구현할 수 있고 싱글톤 패턴을 이용하여 시스템 서비스를 둘러싸면 앱 어디에서나 자원을 공유할 수 있다.
4. LiveData 사용시 주의 할 점
LiveData 객체를 사용하기 위해서는 다음 내용을 알고 있으면 된다.
- Generic을 사용해 관찰하고자 하는 데이터의 타입(Type)을 갖는 LiveData 인스턴스를 생성한다.
(보통 LiveData 객체는 안드로이드 아키텍쳐 패턴의 ViewModel 클래스 내에서 함께 사용된다.) - LiveData 클래스의 observe() 메소드를 사용해 Observer 객체를 LiveData 객체에 "결합"한다. 이 때 observe() 메소드는 LifecycleOwner 객체를 필요로 하며 보통은 Activity를 전달한다.
LiveData에 저장된 데이터에 어떠한 변화가 일어난 경우 결합된 LifecycleOwner에 의해서 상태가 active(활성)인 한 모든 데이터에 대해 Trigger가 발생한다. - Observer 객체를 생성한다.
생성시 LiveData가 들고 있는 데이터가 변화가 일어났을 때 수행해야 할 로직이 들어있는 onChanged() 메소드를 정의해야 한다.
보통은 액티비티나 프래그먼트 같은 UI Controller 내에서 해당 메소드를 생성한다. - observeForever(Observer)를 통해 LifeCycleOwner 없이 Observer를 생성하여 등록할 순 있지만, 이 경우에는 Observer는 항상 active(활성) 상태이므로 데이터 변화를 항상 전달 받는다. 단 removeObserver(Observer)메소드를 통해 Observer를 제거할 수 있다.
5. LiveData의 간단한 사용법 (예제 코드)
앞에서 설명드린 것 처럼 LiveData는 주로 안드로이드 아키텍처 패턴의 ViewModel과 함께 사용되기 때문에, 예제 코드도 ViewModel을 상속받아 클래스 내에서 정의한 LiveData로 작성했다.
예제 코드들은 Kotlin으로 작성하였다.
- ViewModel 클래스 생성
아래의 코드에서는 MutableLiveData를 사용했지만 불변(Immutable)객체로 LiveData<>를 사용해도 상관없다.
class TestLiveDataViewModel : ViewModel() {
// String 타입의 MutableLiveData 생성, by lazy로 초기화는 뒤에
val textValue: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
위에서 만든 ViewModel 클래스 내의 LiveData 객체를 Activity에서 사용을 할텐데 대부분의 경우 LiveData에 Observer를 결합하는 코드는 컴포넌트의 onCreate() 메소드 내에 위치하는 것이 바람직하다.
그 이유는 2가지가 있다.
- 안드로이드 생명주기인 onResume()에 하게될 경우 pause() 나 stop() 에 의해서 잠시 백그라운드 상에서 inactive(비활성화)된 앱이 다시 active(활성화)가 되면서 LiveData에 대한 코드가 중복호출이 될 수 있기 때문이다.
이는 앞에서 설명드렸던 내용들 중에 LiveData의 장점 중 {생명주기에 대한 추가적인 handling을 하지 않아도 됨}에 대해 반대되는 잘못된 방식이다. - 액티비티나 프래그먼트가 active(활성화) 되자마자 UI에 표시 할 수 있는 데이터를 가질 수 있기 때문에 해당 컴포넌트는 STARTED 상태가 되자마자 LiveData 객체로부터 가장 최신의 값을 수신해야 한다.
- 메인 액티비에의 onCreate에 Observer를 세팅한다.
class MainActivity : AppCompatActivity() {
// 전역 변수로 ViewModel lateinit 세팅
private lateinit var model: TestLiveDataViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ViewModel을 가져옵니다.
model = ViewModelProvider(this).get(TestLiveDataViewModel::class.java)
// Observer를 생성한 뒤 UI에 업데이트 시켜 줍니다.
val testObserver = Observer<String> { textValue ->
// 현재 MainActivity에는 TextView가 하나만 존재합니다.
// 다른 데이터를 받는 UI 컴포넌트가 있다면 같이 세팅 해줍니다.
tv_livedata_test.text = textValue
}
// LiveData를 Observer를 이용해 관찰하고
// 현재 Activity 및 Observer를 LifecycleOwner로 전달합니다.
model.textValue.observe(this, testObserver)
}
}
6. 결론
LiveData를 통해서 UI를 업데이트하는 경우 일반적으로 Activity나 Fragment 내에서 직접 선언하는 것보다 위의 예제처럼 ViewModel 내에서 정의하고 호출하여 사용하는 것이 더 좋다.
이유는 다들 ViewModel이 뭔지 알고 계시듯이 액티비티와 데이터 간의 결합도를 낮추고(의존성), UI Controller는 오직 data를 display만 하는 것을 수행하게 하는 안드로이드 아키텍처 패턴(디자인)을 유지하기 위해서이다.
까놓고 말해서 LiveData는 그냥 LiveData만 쓰면 좋은점을 크게 느끼기 힘들다.
하지만 Databinding, ViewModel, RoomDatabase, Reactive Programing등과 함께 쓸 경우 그 진가가 발휘되며 개발자는 아주 편하게 코딩이 가능하기 때문에 UI 출력 데이터에 관한 실수 또한 줄여준다.