[Android] LiveData

혜령·2022년 2월 27일
0

Android 공부하기

목록 보기
8/8

안드로이드 공식문서에서는 LiveData는 관찰이 가능한 데이터 홀더 클래스이며, 수명주기를 인식한다고 설명되어 있습니다.

우선 관찰이 가능하다는 것이 어떤 의미인지 알아보겠습니다.

Observer

LiveData의 메서드에는 observe가 있습니다. 이 함수의 두 번째 전달인자를 통해서 LiveData를 관찰하도록 Observer를 등록해주게 됩니다.

기존에 관찰자가 없다면, 데이터가 변경될 수 있는 코드에 모두 직접 변경 시에 어떻게 UI를 업데이트할지를 작성했어야 합니다. 그렇게되면 새로 불러오고, 추가, 삭제 하는 경우에 계속 일일이 신경을 써줘야 했습니다. 또한 데이터 갱신 작업이 다른 스레드에서 수행되는 경우에는 그 작업을 계속 기다리고 있거나, 제대로 업데이트를 못해주는 일이 발생할 수 있었습니다.

Observer를 사용하게 된다면, 데이터가 변경이 일어나는 것을 관찰을 해주고 UI 업데이트까지 맡기게 될 수 있습니다. 이런 Observer를 사용하기 위해서는 데이터가 LiveData이어야 합니다.

대부분 onCreate()에서 Observer을 등록하는 코드를 넣게 됩니다. onResume()은 중복이 될 수 있고, 활성상태가 되는 즉시 데이터를 표시하기 위함입니다.

LiveData가 가지고 있는 데이터에 변화가 생기면, 등록된 Observer 객체에 변화를 알립니다. 그러면 Observer의 onChanged()메서드가 호출됩니다. 따라서 원하는 작업은 onChanged에 정의해두면 됩니다.

ViewModel

ViewModel이 UI의 데이터를 가지고 관리하는 일을 담당하기 때문에, LiveData 객체를 보유하는데 적합합니다.

그 이후에는 UI 컨트롤러와 ViewModel이 통신을 해야합니다. 하지만 ViewModel에서 UI 컨트롤러의 참조를 가지고 있다면 ViewModel의 생명주기가 UI 컨트롤러의 생명주기보다 길기 때문에 메모리 누수가 발생할 수 있습니다. 따라서 UI 컨트롤러에서 ViewModel의 참조를 가지고 있어야 합니다. 주의할 점은 UI 컨트롤러는 데이터를 표시하는 역할을 하는 것이므로 ViewModel의 참조를 가지고 있어야지, LiveData의 인스턴스를 보유해서는 안 됩니다.

UI 컨트롤러에서 ViewModel에 대한 참조를 가지고, 서로 의사소통이 되어야 합니다. 그러기 위해서 LiveData와 Observer을 사용하게 됩니다. UI 컨트롤러에서 데이터를 관찰하도록 해서 둘 사이의 통신이 가능하도록 한 것입니다.

LiveData

LiveData에는 LiveData와 MutableLiveData로 나뉩니다. MutableLiveData클래스가 LiveData클래스를 상속한 것입니다. 두 클래스의 차이점은 이름에서도 느껴지듯이 MutableLiveData는 get, set이 가능한 읽고 변경이 가능한 데이터이고, LiveData는 get만 가능한 읽기 전용 데이터입니다.

LiveData는 보통 ViewModel과 함께 쓰이며, MVVM패턴을 사용할 수 있도록 해줍니다. 이때, ViewModel과 Repository로 나뉘면서 ViewModel은 변경이 불가능한 LiveData를 가지고 있고, Repository에서 변경가능한 MutableLiveData를 가지고 ViewModel의 LiveData에 대입하는 방식으로 사용을 하게 됩니다.

이렇게 하는 이유는 UI컨트롤러가 값을 직접 수정하지 못하도록 하기 위해서 입니다. UI 컨트롤러는 데이터를 읽기만 하면 되는 것이고, 데이터를 수정하지 않아야 합니다. 따라서 Repository에서 변경하는 값은 MutableLiveData에 저장하고, UI 컨트롤러에서 접근하는 데이터는 LiveData로 저장하고, MutableLiveData 값을 대입하는 방식으로 사용을 하게 됩니다.

정리하자면, LiveData는 public으로 외부에서 사용이 가능하도록 하여 ViewModel과 UI컨트롤러의 연결 통로가 되는 것이고, MutableLiveData는 private으로 내부에서 데이터를 수정하는 역할을 하게 되는 것입니다.

class LoadViewModel : ViewModel() {

    private val _liveData = MutableLiveData<String>()
    val liveData: LiveData<String> get() = _liveData

    fun loadData() = viewModelScope.launch {
        _liveData.value = "value"
        _liveData.postValue("value")
    }
}

보통 MutableLiveData의 변수명 앞에는 를 붙이고, LiveData에는 붙이지 않습니다. 변수명 앞에 를 붙이는 것은 내부 사용용이라는 의미로 하나의 코딩 컨벤션입니다. 따라서 UI 컨트롤러에서 사용되지 않고 내부적으로만 사용하는 MutableLiveData에 _를 붙여서 사용합니다.

하지만 UI컨트롤러에서 꼭 LiveData를 변경시키지 말아야 하는 것은 아닙니다. 변경이 필요한 경우도 있는데, 그런 경우에는 LiveData가 아닌 MutableLiveData를 사용해야 합니다.

setValue() vs postValue()

MutableLiveData는 setValue메서드와 postValue메서드를 사용할 수 있습니다. 두 함수 모두 LiveData에 저장된 값을 수정하기 위한 메서드입니다. 차이점은 setValue는 메인 스레드(기본 스레드)에서 값을 변경할 때 사용하고, postValue는 메인이 아닌 스레드(작업 스레드)에서 값을 변경할 때 사용됩니다. 백그라운드에서 setValue를 한다면 오류가 발생하니까 주의해야 합니다.

postValue는 값을 즉시 설정하는 것이 아닌 Runnable을 통해서 Main Looper를 이용해 값을 보내고, 메인 스레드로 다시 setValue()하는 방식으로 동작합니다. 따라서 즉각적으로 변경을 원하는 경우에는 setValue를 사용합니다. 또한 postValue가 여러 번 호출된다면 모든 값이 적용되는 것이 아닌 가장 최신의 값만 메인 스레드에 적용되게 됩니다.

LifecycleOwner

위에서 LiveData의 observe함수를 보면 첫 번째 전달인자로 LivecycleOwner를 전달하는 것을 볼 수 있습니다. 이 것이 바로 처음에 LiveData에서 설명했던 수명주기를 인식한다는 것과 관련이 있습니다.

LiveData는 UI컨터롤러의 데이터를 담게 됩니다. 따라서 UI컨트롤러가 비활성 상태이거나, 소멸된 이후에는 관찰될 필요가 없습니다. 따라서 LiveData에 Observer를 등록하면서 어떤 Activity나 Fragment의 수명주기를 따를지 같이 등록해주게 됩니다. 그러면 STARTED나 RESUMED상태(활성상태)인 경우에만 변경된 값을 업데이트하게 해줍니다. 또한 DESTROYED된다면 Observer를 삭제해줍니다. 이를 통해서 개발자는 메모리 누수의 걱정을 덜 수 있습니다.

Activity를 LifecycleOwner로 등록한다면 this로 등록하면 됩니다. 하지만 Fragment도 LifecycleOwner를 구현하고 있기에 this로 등록해도 된다고 생각할 수 있지만, 이렇게 되면 문제가 생길 수 있습니다. 이미 이 문제가 파악이 돼서 Fragment에서 this를 사용하면 빨간 밑줄과 안내 메세지가 발생합니다.

그 이유는 Fragment는 onDestroy가 호출되지 않아도 onCreateView가 여러 번 호출될 수 있기 때문입니다. 따라서 복수의 Observer가 호출되는 현상이 발생하게 됩니다.

Frament에는 Fragment Lifecycle과 Fragment View Lifecycle으로 2개의 Lifecycle이 존재합니다.

  • Fragment Lifecycle : Create ~ Destroy
  • Fragment View Lifecycle : createView ~ destroyView

위에서 알 수 있듯이 Fragment가 Fragment View보다 긴 수명주기를 가지고 있고, UI 업데이트는 Fragment View Lifecycle이 적당합니다. 따라서 LiveData에서도 Fragment View로 LifecycleOwner를 지정한다면 복수의 Observer를 호출하는 문제를 방지할 수 있습니다.

사용 시 장점

안드로이드 공식문서에서 설명한 LiveData의 장점에 대해서 살펴봅니다.

UI와 데이터 상태의 일치 보장

LiveData는 옵저버(관찰자)패턴을 따릅니다. LiveData는 기본 데이터가 변경될 때 Observer객체에 알립니다. 코드를 통합하여 이러한 Observer객체에 UI를 업데이트할 수 있습니다. 이렇게 하면 앱 데이터가 변경될 때마다 관찰자가 대신 UI를 업데이트하므로 개발자가 업데이트할 필요가 없습니다.

메모리 누수 없음

관찰자는 Lifecycle객체에 결합되어 있으며 연결된 수명 주기가 끝나면 자동으로 삭제됩니다.

중지된 활동으로 인한 비정상 종료 없음

활동이 백 스택에 있을 때를 비롯하여 관찰자의 수명 주기가 비활성 상태에 있으면 관찰자는 어떤 LiveData 이벤트도 받지 않습니다.

수명 주기를 더 이상 수동으로 처리하지 않음

UI 구성요소는 관련 데이터를 관찰하기만 할 뿐 관찰을 중지하거나 다시 시작하지 않습니다. LiveData는 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하므로 이 모든 것을 자동으로 관리합니다.

최신 데이터 유지

수명 주기가 비활성화되면 다시 활성화될 때 최신 데이터를 수신합니다. 예를 들어 백그라운드에 있었던 활동은 포그라운드로 돌아온 직후 최신 데이터를 받습니다.

적절한 구성 변경

기기 회전과 같은 구성 변경으로 인해 활동 또는 프래그먼트가 다시 생성되면 사용 가능한 최신 데이터를 즉시 받게 됩니다.

리소스 공유

앱에서 시스템 서비스를 공유할 수 있도록 싱글톤 패턴을 사용하는 LiveData객체를 확장하여 시스템 서비스를 래핑할 수 있습니다. LiveData객체가 시스템 서비스에 한 번 연결되면 리소스가 필요한 모든 관찰자가 LiveData객체를 볼 수 있습니다.

References

https://developer.android.com/topic/libraries/architecture/livedata#work_livedata

https://comoi.io/300

https://thdev.tech/android/2021/02/01/LiveData-Intro/

https://velog.io/@jojo_devstory/Android-LiveData...넌-누구냐

https://wooooooak.github.io/android/2019/06/11/Android_liveData_value/

profile
안녕하세요

0개의 댓글