[Android] LiveData

민채·2024년 2월 16일
0

Android

목록 보기
5/16

LiveData

  • 관찰 가능한 Date Holder 클래스
  • 일반적인 Observable과는 다르게 LiveData는 LifeCycle을 인식
  • Activity, Fragment와 같은 컴포넌트의 생명주기를 인식하여 active한 상태일 때만 데이터를 업데이트
  • 등록된 Observer 객체에 변화를 알려주고, Observer의 onChanged() 메서드가 실행
  • 데이터 값이 바뀌었을 때 알아서 감지해서 화면을 갱신
  • Observer Pattern을 사용하는 대표적인 예시 중 하나

동작 방식

LiveData는 LifeCycleOwner을 통해 Lifecycle을 알고있음

  1. LiveData는 observe()메소드를 사용해 Observer 객체와 결합함
  2. 이때 observe()는 LifeCycleOwner를 필요로 하고 보통 Activity나 Fragment를 전달함
  3. 해당 화면 별 생명주기에 따라 LiveData가 동작

LifeCycleOwner

  • 단일 메소드 인터페이스
  • 생명 주기를 관리
  • Activity나 Fragment에서 이를 상속하고 있음
  • LiveData와 ViewModel과 함께 쓰임

장점

  • UI와 데이터 상태의 일치 보장
    • LiveData는 기본 데이터가 변경될 때 Observer 객체에 알림
    • 앱 데이터가 변경될 때마다 Observer가 대신 UI를 업데이트하므로 직접 업데이트 할 필요 없음
  • 메모리 누수 없음
    • Observer는 Activity나 Fragment의 Lifecycle을 따름
    • LifeCycle이 소멸될 경우 자동으로 삭제 -> 따로 메모리를 해체하거나 삭제하지 않아도 됨
  • 중지된 활동으로 인한 비정상 종료 없음
    • 활동이 backstack에 있을 때를 비롯하여 관찰자의 Lifecycler이 비활성 상태에 있으면 Observer는 어떤 LiveData 이벤트도 받지 않음
  • 수명 주기를 더 이상 수동으로 처리하지 않음
    • UI 구성요소는 관련 데이터를 관찰하기만 할 뿐 관찰을 중지하거나 다시 시작하지 않음
    • LiveData는 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하므로 이 모든 것을 자동으로 관리
  • 항상 최신 데이터 유지
    • Lifecycle이 비활성화되면 다시 활성화될 때 최신 데이터를 수신 -> 백그라운드에 있다가 포그라운드로 오는 경우 최신 데이터를 받아옴
  • 적절한 구성 변경
    • 기기 회전과 같은 구성 변경으로 인해 활동 또는 Fragment가 다시 생성되면 사용 가능한 최신 데이터를 즉시 받음
  • 리소스 공유
    • 싱글톤 패턴을 이용하여 시스템 서비스를 래핑하면 앱 어디에서나 리소스를 공유 할 수 있음

사용법

  • 일반적으로 ViewModel과 함께 사용

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 공식 문서

profile
코딩계의 떠오르는 태양☀️

0개의 댓글