LiveData
- 관찰 가능한 Date Holder 클래스
- 일반적인 Observable과는 다르게 LiveData는 LifeCycle을 인식
- Activity, Fragment와 같은 컴포넌트의 생명주기를 인식하여 active한 상태일 때만 데이터를 업데이트
- 등록된 Observer 객체에 변화를 알려주고, Observer의 onChanged() 메서드가 실행
- 데이터 값이 바뀌었을 때 알아서 감지해서 화면을 갱신
- Observer Pattern을 사용하는 대표적인 예시 중 하나
동작 방식
LiveData는 LifeCycleOwner을 통해 Lifecycle을 알고있음
- LiveData는 observe()메소드를 사용해 Observer 객체와 결합함
- 이때 observe()는 LifeCycleOwner를 필요로 하고 보통 Activity나 Fragment를 전달함
- 해당 화면 별 생명주기에 따라 LiveData가 동작
LifeCycleOwner
- 단일 메소드 인터페이스
- 생명 주기를 관리
- Activity나 Fragment에서 이를 상속하고 있음
- LiveData와 ViewModel과 함께 쓰임
장점
- UI와 데이터 상태의 일치 보장
- LiveData는 기본 데이터가 변경될 때 Observer 객체에 알림
- 앱 데이터가 변경될 때마다 Observer가 대신 UI를 업데이트하므로 직접 업데이트 할 필요 없음
- 메모리 누수 없음
- Observer는 Activity나 Fragment의 Lifecycle을 따름
- LifeCycle이 소멸될 경우 자동으로 삭제 -> 따로 메모리를 해체하거나 삭제하지 않아도 됨
- 중지된 활동으로 인한 비정상 종료 없음
- 활동이 backstack에 있을 때를 비롯하여 관찰자의 Lifecycler이 비활성 상태에 있으면 Observer는 어떤 LiveData 이벤트도 받지 않음
- 수명 주기를 더 이상 수동으로 처리하지 않음
- UI 구성요소는 관련 데이터를 관찰하기만 할 뿐 관찰을 중지하거나 다시 시작하지 않음
- LiveData는 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하므로 이 모든 것을 자동으로 관리
- 항상 최신 데이터 유지
- Lifecycle이 비활성화되면 다시 활성화될 때 최신 데이터를 수신 -> 백그라운드에 있다가 포그라운드로 오는 경우 최신 데이터를 받아옴
- 적절한 구성 변경
- 기기 회전과 같은 구성 변경으로 인해 활동 또는 Fragment가 다시 생성되면 사용 가능한 최신 데이터를 즉시 받음
- 리소스 공유
- 싱글톤 패턴을 이용하여 시스템 서비스를 래핑하면 앱 어디에서나 리소스를 공유 할 수 있음
사용법
https://junghun0.github.io/2019/05/22/android-viewmodel/
- 값을 전달할 때
postValue
, setValue
를 사용
아래 코드와 같이 값을 관찰
viewModel.liveData.observe(this) {
println(it)
}
MutableLiveData
- LiveData를 상속받는 클래스
- LiveData에 postValue와 setValue를 추가한 클래스
- MutableLiveData는 말 그대로 값의 수정이 가능하고 LiveData는 값의 수정이 불가능
setValue()
- MainThread(UI)가 보장될 경우에 사용 (MainThread 에서의 값 업데이트)
- MainThread 가 아닌 곳에서 이를 활용할 경우 런타임 시 오류가 발생
setValue()
의 내부 코드
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
postValue()
- MainThread가 아닌 IO 스케쥴러를 활용하는 경우에 사용 (MainThread 로 값 전달)
- 마지막에 postToMainThread() 를 호출함으로써 MainThread 로 값을 전달
postValue()
의 내부 코드
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
- 아래의
postToMainThread
객체의 내부 코드를 보면 run()
이 호출 되면서 setValue()
가 실행되어서 LiveData 값을 변경
Runnable
객체의 내부 코드
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
LiveData는 항상 MainThread로 값을 처리!
-> ViewModel 보다 더 하위 객체인 Repository 와 같은 내부에서 LiveData를 통해 값을 가져오거나 또는 UI 업데이트가 없는 곳에서 LiveData를 활용하는 것은 잘못된 방법
예제
안드로이드 MVVM 패턴 연습 프로젝트
참조
LiveDate 공식 문서