서두
해당 포스트는 Android Jetpack 중 하나인 LiveData 에 대해서 정리한 것입니다.
LiveData
LiveData 는 Android MVVM 디자인 패턴을 구현하기 위해서 사용되는 컴포넌트입니다.
만약 Android MVVM 디자인 패턴을 구현 할 때에는 보통 아래와 같이 set로 묶어서 사용합니다.
그 중 LiveData는 Data 를 저장하고 관라하는 역할을 수행합니다.
LiveData 특징
- 관찰가능한 객체로 observer 를 등록하여 최신의 data를 수신을 할수 있습니다.
- LiveData 의 값을 단순히 변경만 함으로써 내부적으로 등록된 observer 에게 자동으로 notify 를 합니다.
- Data 가 변경되었을 시 모든 observer 에게 전달하는 것이 아니라 현재 활성 상태인 객체에 대해서만 전달이 됩니다. 이것이 가능한 이유는 LiveData 에 observer 를 등록할 때
lifecycleOwner
를 같이 넘겨주기 때문입니다.
LiveData 장점
- UI와 데이터 상태의 일치 보장 : LiveData 는 데이터가 변경이 되면 자동으로 observer에 notify 가 전달이 되고 notify를 받을 때 UI를 바로 업데이트가 가능합니다. 따라서 데이터와 UI 상태를 일치 시킬수 있습니다.
- 중지된 활동으로 인한 비정상 종료 없음 : 액티비티나 프래그먼트가 백그라운드에 있어 비활성화 상태일 경우 어떤 LiveData 이벤트를 받지 않습니다.
- 최신 데이터 유지 : 수명 주기가 비활성화되면 다시 활성화될 때 최신 데이터를 수신합니다. 예를 들어 백그라운드에 있었던 액티비티는 포그라운드로 돌아온 직후 최신 데이터를 받습니다.
- 메모리 누수 없음 : 액티비티나 프래그먼트가 LiveData 를 옵저빙하고 있는 상태에서 생명 주기가 종료가 되면 자동으로 옵저빙을 해제를 합니다.
LiveData 생성
LiveData는 ViewModel class의 맴버 변수로 선언을 하여 View Model이 가지고 있도록 합니다.
class NameViewModel : ViewModel() {
// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
// Rest of the ViewModel...
}
View Model 에서 LiveData를 저장하는 이유
- 액티비티나 플래그먼트가 지나치게 커지니 않기 위해서 입니다. UI 컨트롤러가 데이터 표시를 담당하자만 데이터 상태를 보유하지 않습니다.
- LiveData 인스턴스를 특정 액티비티나 프래그먼트 인스턴스의 생명주기와 분리하여 LiveData 인스턴스를 계속 유지하기 위해서입니다.
LiveData 값 변경
현재 메인 쓰레드(UI thread) 일 경우 setValue() 를 사용하고 Working 쓰레드 일 경우 postValue() 를 사용합니다.
참고로 postValue() 는 내부적으로 메인 쓰레드 핸들러로 메시지를 던지는 구조입니다.
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
LiveData 옵저빙
observe() 메소드를 이용하며 lifecycleOwner
, Observer
인터페이스를 인자로 넘깁니다.
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
val counterTextView = findViewById<TextView>(R.id.counter)
viewModel.getCounter()
.observe(this, { count ->
counterTextView.text = "count : $count"
})
Observer
콜백이 실행되는 쓰레드는 메인 쓰레드이기 때문에 바로 UI 업데이트가 가능합니다.
LiveData 는 액티비티나 프래그먼트의 lifecycleOwner
를 가지고 있으며 LiveData 가 변경된다고 무조건 옵저버에게 전달되는 것이 아니라 아래 코드와 같이 항상 상태를 체크하며 lifecycleOwner
의 상태가 START, RESUME 일 때에만 변경 사실이 notify가 됩니다.
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
LiveData 변환
Transformations
를 사용하여 LiveData에 저장된 값을 다른 값으로 변환하는 것이 가능합니다.
val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = Transformations.map(userLiveData) {
user -> "${user.name} ${user.lastName}"
}
LiveData 병합
두 가지 이상의 LiveData를 결합하여 하나의 LiveData로 변경하고 싶은 경우 MediatorLiveData
를 사용합니다.
MediatorLiveData
LiveData 의 서브 클래스로써 한 개 이상의 liveData 를 관찰하고 관찰하고 있는 LiveData가 변경될 경우 등록한 onChange() 콜백이 호출이 되는 형식입니다.
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
정리
LiveData 를 사용하는 목적은 Android Observer 패턴을 구현함에 있어서 개발 시간을 단축시킬수 있다는 장점이 있습니다.
만약 LiveData 를 사용하지 않는 경우 한 개의 data에 대해서 listener 를 여러 개를 등록/해제를 시킬수 있는 중간 관리자 객체가 필요하게 됩니다.
중간 관리자 객체는 listener callback이 메인 쓰레드에서 호출이 될 수 있도록 쓰레드 스위칭까지 고려해야 합나디.
data를 관찰하는 액티비티나 프래그먼트는 메모리 누수가 발생하지 않도록 하기 위해 생명 주기가 종료되기 전에 반드시 listener를 해제를 해야 합니다.
따라서 LiveData 를 사용함으로써 위에 언급된 동작을 개발자가 따로 고려하지 않아도 된다는 장점을 제공합니다.
댓글남기기