#LiveData 공식문서 링크
https://developer.android.com/topic/libraries/architecture/livedata?hl=ko
아래 설명은 MVVM 패턴에서 LiveData를 사용한다는 전제에서 작성되었습니다. Live Data는 안드로이드 플랫폼에 종속적이기 때문에 생명주기를 잘 활용하고 싶다면 LiveData를 활용한느 것이 좋습니다. LiveData는 StateFlow랑 비교가 되는데 이는 LiveData Vs StateFlow 글에 포스팅 되어있습니다.
#TIP
코틀린 1.4 이상 버전을 사용하시면 더 이상 확장함수를 사용하여 LiveData를 사용하지 않아도 되기때문에 "import androidx.lifecycle.observe"를 호출하여 사용하지 않아도 됩니다.
즉 , implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"를 작성하지 않아도 됩니다.
#0. 구독자
아래에서 설명되는 구독자는 Observer 클래스의 객체라고 생각하시면 됩니다. 공식문서에서는 관찰자라고 표현되어 있지만 저는 구독자라는 개념이 데이터를 받아오는 관점에서 더 어울리는 표현이라고 생각하여 구독자라는 워딩을 사용하였습니다. 관찰자라는 단어를 사용하면 데이터를 직접 가져오는 듯한 의미가 내포 되어 있는 듯하였기 때문입니다.
#1. LiveData란?
LiveData란 관찰 가능한 데이터 홀더 클래스라고 정의되어 있다.
관찰 가능한 데이터 홀더 클래스라는 의미는 , LiveData의 데이터가 변경이 있을 때 해당 LiveData를 구독하고 있는(참조하고 있는) Observer객체에 LiveData의 변경된 데이터가 반영된다는 의미입니다.
아래의 코드에 , LiveData의 <>에 타입을 넣어주는 코드가 있는데 이처럼 LiveData가 데이터를 홀더하고 있는 역할을 한다.
#2. 구독의 의미
구독의 의미란 신문 구독을 하면 단지 받아오는 것만 가능한 것처럼 , 구독자는 변경되는 데이터의 값을 받아오기만 할 뿐 변경하는 것은 불가능함을 내포하고 있으며 , 만약 데이터를 변경하고 싶다면 ViewModel에 작성된 함수를 사용하면 변경 할 수 있다.
#3. LiveData의 예시
예를 들어 LiveData로 ViewModel에서 선언된 변수가 있을 때에 , 해당 변수를 다른 클래스에서 참조하여 사용하고 있을 경우 , 만약 해당 변수에 저장된 값이 변경된다면 해당 변수를 참조하고 있는 녀석 또한 변경된 값을 반영한다는 것입니다.
// ViewModel에서 LiveData를 사용하여 변수를 선언한 후에 // 아래코드는 LiveData가 데이터 홀더 클래스로 사용되는 예시 코드 private val _latestWord = MutableLiveData<ExcerciseModel>() val latestWord: LiveData<ExcerciseModel> = _latestWord // 아래 코드는 LiveData가 참조된(구독된) 코드 excerciseViewModel.latestWord.observe(this, Observer { excercise -> excercise?.let { excerciseAdapter.list.add(0, it) excerciseAdapter.notifyItemInserted(0) } }) // 아래 코드는 함수를 사용하여 데이터의 값을 변경하는 예시 코드이다. fun updateAddWord() = viewModelScope.launch { val resulet = getLatestWordUseCase() _latestWord.value = resulet }
#4. LiveData 기초 개념 정리
이러한 과정에서 참조하고 있는 녀석을 구독자라고 칭하며 , LiveData는 구독의 대상이 되는 데이터를 내장하고 있는 데이터 홀더 클래스라고 불려진다.
#5.LiveData 특징
LiveData는 다른 클래스와 다르게 생명주기라는 것을 인지합니다. 이는 안드로이드 클래스의 수명주기를 인지하고 있다는 것인데 , 이러한 특징으로 인해 생명주기가 STARTER || RESUMED 상태일때의 구독자에게 데이터를 업데이트 해줍니다. 이러한 구독자를 활성된구독자라고 불립니다.
비활성화된 구독자는 변경된 데이터를 받지 못하므로 메모리 누수를 방지 할 수 있으며 리소스를 절약 할 수 있습니다.
LifecycleOwner를 사용하여 구독자를 삭제 할 수 도 있습니다.
주로 Activity와 Fragment에서 사용되며 , 해당 클래스의 수명주기가 DESTROYED로 변경될 때 구독자가 삭제되며 해당 구독자는 비활성화된 구독자라고 불립니다.
안드로이드 클래스는 LifecycleOwner 인터페이스가 구현되어 있기 때문에 .observe()함수의 파라미터에 this를 작성하시면 됩니다.
viewmodel.exampleData.observe(LifecycleOwner 객체) { 전달된 데이터 -> }
이런식으로 구독 할 수 있으며 후행람다를 통해 전달된 데이터를 사용 할 수 있습니다. 코틀린에서는 observe 메서드를 오버로딩 된 확장 함수를 제공 하기 때문에 확장 함수 내부에서 Observer 객체가 반환되기 때문에 위와 같이 사용 할 수 있습니다. 만약 없었더라면 직접 Observer 객체를 생성하여 observe 메서드의 두번째 파라미터로 전달해야 합니다.
아래코드 참고하면 ㄱ.자바로 작성된 LivdData 코드 , ㄴ.코틀린으로 작성된 LiveData 확장함수 에 대한 설명이 있습니다.
아래코드는 자바로 작성된 LiveData 코드
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } owner.getLifecycle().addObserver(wrapper); }
위 코드에서 보이는 것 처럼 자바를 사용할 경우에는 Observer객체를 생성해줘야 합니다.
아래 코드는 코틀린으로 작성된 LiveData 확장함수
@Deprecated( "This extension method is not required when using Kotlin 1.4. " + "You should remove \"import androidx.lifecycle.observe\"" ) @MainThread public inline fun <T> LiveData<T>.observe( owner: LifecycleOwner, crossinline onChanged: (T) -> Unit ): Observer<T> { val wrappedObserver = Observer<T> { t -> onChanged.invoke(t) } observe(owner, wrappedObserver) return wrappedObserver }
하지만 코틀린에서는 확장함수를 제공하여 후행람다식을 사용하여 Observer 객체를 람다식에서 받아서 사용 할 수 있습니다.
해당 객체는 wrappedObserver라는 변수에 저장되어 반환됩니다.
하지만 코틀린 1.4 버전 이후에는 코틀린 언어 자체체적으로 타입 추론 기능 능력이 강화? 업그레이드 되면서 타입을 명시적으로 작성하지 않아도 컴팡리러가 올바른 타입을 자동으로 추론 할 수 있기 때문에 확장함수를 사용하지 않고도 LiveData를 편리하게 사용 할 수 있습니다.
따라서 implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"를 빌드 코드에 넣지 않아도 라이브데이터를 사용하는 것이 가능합니다.
LiveData는 옵절브 패턴을 따르기 때문에 LiveData는 기본 데이터가 변경될 때 Observer 객체에 알려줍니다. 그러면 구독자인 Observer객체가 변경된 데이터를 받아서 사용합니다.
구독자가 LifeCycle에 결합되어 있으므로 수명주기가 파괴되면 구독자가 비활성화된 구독자로 변경되어 메모리 누수를 방지 할 수 있으며 , 비정상 종료 에러를 방지 할 수 있습니다.
생명주기가 결합되어 있으므로 수동으로 관리하지 않아도 됩니다.
만약 비활성화된 구독자가 활성화된 구독자로 변경된다면 최신의 데이터를 수신하여 개발자가 이점을 신경쓰지 않아도 됩니다.
LiveData는 Public Method가 존재하지 않지만 MutableLiveData 클래스를 사용한다면 setValue와 postValue를 사용 할 수 있지만 LiveData는 ViewModel에서 사용되는 경우가 많으므로 신경쓰지 않으셔도 됩니다.
LiveData는 비동기 데이터 스트림을 직접적으로 처리 할 수 없습니다. 기본적으로 LiveData는 메인 스레드에서 작동하도록 설계되었기 때문인데 이는 코루틴과 플로우를 사용하면 비동기 데이터 스트림 처리를 사용 할 수 있습니다.