[Android/Jetpack] AAC - LiveData
LiveData
식별 가능한(Observable) 데이터 홀더 클래스
LiveData는 Activity, Fragment, Service 등 다른 앱 구성요소의 수명 주기를 고려(Lifecycle-aware)한다.
수명 주기 인식을 통해 LiveData는 활성(active) 수명 주기 상태에 있는 앱 구성요소 Observer만 업데이트한다.
→ Observer 객체가 STARTED나 RESUMED 상태이면 LiveData는 Observer를 활성 상태로 간주함
LifecycleOwner 인터페이스를 구성하는 객체와 페어링된 Observer를 등록할 수 있다.
→ Observer에 상응하는 Lifecycle 객체가 DESTROYED 상태로 변하면 Observer를 삭제할 수 있음
→ Activity와 Fragment가 LiveData 객체를 안전하게 관찰하고 수명주기가 끝나는 즉시 수신 거부되어 누수 걱정X
위의 내용이 이해가 잘 되지 않는다면 이전 포스팅의 AAC-Lifecycle에서 확인하자!
LiveData 사용의 장점
- UI와 데이터 상태의 일치 보장
- LiveData는 observer 패턴을 따름 → LiveData는 기본 데이터가 변경될 때 Observer 객체에 알림.
코드를 통합하여 이러한 Observer 객체가 UI를 업데이트할 수 있음. - 앱 데이터가 변경될 때마다 Observer 객체가 대신 UI를 업데이트 하므로 개발자가 업데이트를 할 필요 없음
- LiveData는 observer 패턴을 따름 → LiveData는 기본 데이터가 변경될 때 Observer 객체에 알림.
- 메모리 누수(Memory leak) 없음
- Observer는 Lifecycle 객체에 결합되어 있으며 연결된 수명 주기가 끝나면 자동으로 삭제됨
- Stop 상태의 Activity와 crash가 발생하지 않음
- Activity가 백스택에 있을 때를 비롯하여 수명 주기가 비활성 상태에 있으면 관찰자는 어떤 LiveData 이벤트도 받지 않음
- 수명 주기를 더 이상 수동으로 처리하지 않음
- UI 구성요소는 관련 데이터를 관찰하기만 할 뿐 관찰을 중지하거나 다시 시작하지 않음
- LiveData는 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하기 때문에 이 모든 것을 자동으로 관리함
- 최신 데이터 유지
- 수명 주기가 비활성화되면 다시 활성화될 때 최신 데이터를 수신함
- 기기 회전과 같은 구성 변경으로 인해 Activity 또는 Fragment가 다시 생성되면 사용 가능한 최신 데이터를 즉시 받음
- 리소스 공유
- 앱에서 시스템 서비스를 공유하도록 싱글톤 패턴을 사용하는 LiveData 객체를 확장하여 시스템 서비스를 랩핑할 수 있음
- LiveData 객체가 시스템 서비스에 한 번 연결되면 리소스가 필요한 모든 관찰자가 LiveData 객체를 볼 수 있음
LiveData 사용 방법
- 특정 유형의 데이터를 보유할 LiveData의 인스턴스 생성 (일반적으로 ViewModel 클래스에서)
- onChanged() 메서드를 정의하는 Observer 객체 생성
- onChanged() : LiveData 객체가 보유한 데이터 변경 시 발생하는 작업 제어
- Activity나 Fragment 같은 UI 컨트롤러에 Observer 객체 생성
- observe() 메서드를 사용하여 LiveData 객체에 Observer 객체를 연결
- observe()는 LifecycleOwner 객체 사용 → Observer 객체가 LiveData 객체를 구독하여 변경사항에 관한 알림을 받음
- Activity나 Fragment와 같은 UI 컨트롤러에 Observer 객체를 연결
LiveData 객체 생성
LiveData는 Collections를 구성하는 List와 같은 객체를 비롯하여 모든 데이터와 함께 사용할 수 있는 Wrapper일반적으로 ViewModel 객체 내에 저장되어 getter 메서드를 통해 접근됨
class TestViewModel : ViewModel() {
// String 타입의 LiveData 생성
// by lazy를 통해 초기화는 나중에
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
*MutableLiveData와 LiveData?
Mutable은 말 그대로 변경이 가능한 것이므로 get/set을 모두 사용할 수 있지만 LiveData는 get만 가능
→ ViewModel은 언제나 값의 변경이 일어나고 다시 읽을 수 있는 상태로 사용하는 것이고, View는 값의 읽기만 허용하는 것(MVVM)
하지만 필요에 따라 View에서도 값의 변경이 일어나야 한다면 Mutable을 사용할 수 있다.
LiveData 객체 관찰
대부분의 경우 앱 구성요소의 onCreate() 메서드는 LiveData 객체 관찰을 시작하기 적합한 곳임
- 시스템이 Activity나 Fragment의 onResume() 메서드에서 중복 호출을 하지 않도록 하기 위해서
- Activity나 Fragment에 STARTED 상태가 되는 즉시 관찰하고 있던 LiveData 객체에서 최신 값을 수신하기 위해서
observer가 업데이트 되는 경우 2가지 :
'LiveData의 데이터가 변경될 때'와 'observer가 비활성→활성으로 상태 변경될 때'
class MainActivity : AppCompatActivity() {
// 'by viewModels()'를 사용하여 Kotlin 프로퍼티를 위임
// activity-ktx artifact
private val model: TestViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// UI를 업데이트하는 observer 생성
val testObserver = Observer<String> { newName ->
// UI 업데이트
textView.text = newName
}
// LiveData를 Observer를 이용하여 관찰하고
// LifecycleOwner로써 현재 Activity와 obsever를 전달
model.currentName.observe(this, testObserver)
}
}
- testObserver를 매개변수로 전달하여 observe()를 호출하면 onChanged()가 즉시 호출되어 currentName에 저장된 최신 값을 제공함
- LiveData 객체가 currentName에 값을 설정하지 않았다면 onChanged()는 호출되지 않음
LiveData 객체 업데이트
LiveData는 저장된 데이터를 업데이트하기 위해 공개적으로 사용할 수 있는 메서드는 없음
대신, MutableLiveData 클래스는 setValue(T)나 postValue(T) 메서드를 public으로 하여 저장된 값을 수정할 수 있도록 함
→ 모든 경우에 해당 메서드들을 호출하면 observer가 트리거되고 UI가 업데이트 됨 (== onChanged() 메서드가 호출됨)
- setValue(T) : MainThread(UI)가 보장될 경우
- postValue(T) : MainThread가 아닌 IO 스케줄러를 활용하는 경우(worker 스레드)
두 메소드 모두 값을 MainThread에 전달하도록 처리하는 것이기 때문에 항상 MainThread에서 사용할 값을 보증함
→ 데이터의 처리가 IO에서 발생해야 하는 경우라면 LiveData 활용은 맞지 않는 것
Room으로 LiveData 사용
- Room 라이브러리는 Observable 쿼리(DAO의 일부)를 지원하며 이 쿼리는 LiveData 객체를 반환함
- DB가 업데이트될 때 Room에서는 LiveData 객체를 업데이트하는 데 필요한 모든 코드를 생성
- 생성된 코드는 필요할 때 백그라운드 스레드에서 비동기적으로 쿼리를 실행
- 이 패턴은 UI에 표시된 데이터와 DB에 저장된 데이터의 동기화를 유지하는데 유용
*Room에 대한 내용은 계속되는 포스팅에서 다룰 예정임!
LiveData 확장
- onActive() 메서드 : LiveData 객체에 active 상태의 observer가 있을 때 호출됨 (업데이트 관찰을 해야 함)
- onInactive() 메서드 : LiveData 객체에 active 상태의 observer가 없을 때 호출됨 (연결된 상태를 유지할 필요가 없음)
- setValue(T) 메서드 : LiveData 인스턴스의 값을 업데이트하고 모든 active 상태의 관찰자에게 변경사항을 알림
by lazy 등 kotlin의 프로퍼티 초기화에 대한 내용은 아래 포스팅 참고
reference >