[Android] Jetpack - LiveData - 1

반응형

출처 : https://tudip.com/blog-post/livedata-android/

이번에는 Jetpack 구성 요소 중 LiveData라는 것에 대해 정리해보려고 합니다.

 

LiveData란?

LiveData란 데이터를 관찰할 수 있는 Holder 클래스 입니다. 추가적인 특징은, Lifecycle 모듈과 같이 Activity, Fragment, Service와 같은 Component의 수명 주기를 인식합니다. (lifecycle-aware)

 

또한, LiveData는 수명 주기가 STARTED 혹은 RESUMED 상태인 경우 Observer 클래스를 사용하여 활성화 합니다. 그리고 활성화된 Observer에게만 상태를 전달합니다. LiveData에 등록이 되어있지만, 비활성화된 Observer는 변화에 대해 알려주지 않습니다.

 

LiveData는 LifecycleOwner 인터페이스를 구현한 객체와 짝으로 Observer를 등록할 수 있습니다. 이를 통해 수명 주기가 상태가 DESTROYED 되었을 때 위의 관계를 삭제할 수 있습니다. 이는 Activity 혹은 Fragment에서 유용한데, LiveData 객체를 안전하게 관리할 수 있습니다.

 

The advantages of using LiveData

  • UI와 데이터 상태가 일치하는지 확인이 가능합니다.
    • LiveData는 Observer 객체에서 UI를 업데이트를 하기위해 코드를 통합하는 것이 가능합니다.
    • UI를 업데이트 하기 위해 매번 앱 데이터를 변경하지 않아도 됩니다.
  • 메모리 누수가 없다.
    • Obserser가 Lifecycle 객체에 바인딩 되어있고, 연결된 수명 주기가 종료되면 스스로 정리합니다.
  • 중지된 Activity로 인한 충돌이 없다
    • Observer의 수명주기가 비활성화이면 (ex) Activity의 Back Stack), LiveData 이벤트를 받지 않습니다.
  • 직접 수명주기 관리가 없다
    • UI 컴포넌트는 관련된 데이터를 관찰하기만 하고, 관찰을 중지하거나 재 시작 하지 않습니다
    • LiveData는 관련된 수명주기 상태가 변경되었다는 것을 감지한 후로 자동으로 관리합니다. 
  • 항상 최신 데이터를 유지합니다.
    • 수명주기가 비활성화 된다면, 다시 활성화 되고 최신 데이터를 전달받습니다.
      예시) Background에 있는 Activity가 Foreground로 전환 즉시 최신 데이터를 전달받습니다.
  • 적절한 구성 변경
    • Activity 혹은 Fragment가 구성 변경(장치 회전 등) 으로 인해 재 생성 되었다면, 즉시 최신으로 사용가능한 데이터를 전달받습니다.
  • 리소스 공유
    • Singleton 패턴을 사용함으로써 LiveData를 확장하고, 앱에서 공유할 수 있도록 시스템 서비스를 래핑할 수 있습니다.
    • LiveData를 시스템 서비스에 한번 연결하고, 리소스가 필요한 Observer는 LiveData 객체를 참조할 수 있습니다.

 

Work with LiveData object

LiveData 객체 사용을 위한 순서

  1. 데이터의 특정 타입을 가지고 있기 위해 LiveData 인스턴스를 생성한다. 일반적으로 ViewModel 클래스에서 수행합니다.
  2. Observer 클래스를 생성하고, LiveData가 가지고 있는 데이터 변경이 있을 때, 어떻게 해야하는지 관리하기 위해  onChanged() 함수를 정의 합니다. 일반적으로 Acitivty 혹은 Fragment와 같은 UI 컨트롤러에 생성합니다.
  3. observe() 함수를 사용하기 위해 Observer 객체를 LiveData 객체에 연결합니다. observe()는 LifecycleOwner 객체를 사용합니다.
    이렇게 하면, Observer 객체를 LiveData 객체에 연결되어 변경사항을 알 수 있습니다. 일반적으로 Acitivty 혹은 Fragment와 같은 UI 컨트롤러에 연결합니다.

LiveData 객체에 저장된 값을 업데이트할 때, 연결되어있는 LifecycleOwner가 활성 상태라면, 등록된 모든 Observer에 트리거합니다.

 

LiveData는 UI 컨트롤러 Obserer가 업데이트 사항을 알 수 있게 허용합니다. LiveData가 가지고 있는 데이터가 변경되었을 때 UI는 자동으로 응답을 합니다.

LiveData 객체 생성

LiveData는 List같은 Collections로 구현된 객체를 포함한 모든 데이터를 사용할 수 있는 래퍼입니다. LiveData 객체는 일반적올 ViewModel 객체에 저장되어있고, getter 함수로 접근합니다.

class NameViewModel : ViewModel() {

    // Create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}

** Activity나 Fragment가 아닌 ViewModel 객체에 LiveData를 작성하는 이유

  • Activity나 Fragement가 커지는 것을 방지하기 위해서 입니다. UI 컨트롤러는 데이터를 출력하는 역할이지 데이터 상태를 가지고 있는 역할은 아닙니다.
  • 특정 Activity나 Fragment와 LiveData 인스턴스를 분리하고, LiveData 객체가 구성 변경에도 값이 유지되게 하기 위해서 입니다.

LiveData 객체 관찰

onCreate() 함수는 아래의 이유로 관찰하는 위치로 적절하게 사용됩니다.

  • Activity 혹은 Fragment의 onResume는 중복 호출을 할 가능성이 있습니다.
  • Activity 혹은 Fragment가 데이터를 가지고 있게 하여, 활성화 되자마자 데이터를 확인하기에 좋습니다. 앱 컴포넌트가 STARTED 상태가 되자마자, 관찰중인 LiveData로부터 가장 최근의 값을 받습니다.

LiveData는 일반적으로 데이터가 변경되거나 Observer가 활성화 될때 업데이트된 사항을 전달합니다. 즉, 비활성 상태에서 활성 상태로 변경될 시에 Observer는 업데이트된 사항을 전달받습니다.

 

예시) LiveData 객체를 관찰하기 시작하는 코드

class NameActivity : AppCompatActivity() {

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}

위의 코드 중, nameObserver 파라미터와 함께 observe() 함수가 호출된 후에는, onChanged()가 호출되고  mCurrentName에 저장된 가장 최근 값을 알 수 있습니다.

mCurrentName값이LiveData에 의해 설정되지 않은 경우 onChanged()가 호출되지 않습니다.

 

LiveData 객체 업데이트

LiveData는 저장된 데이터를 업데이트하기 위해 코드레벨에서 사용할 수 있는 함수는 없습니다.

하지만, MutableLiveData 클래스는 setValue(T)와 postValue(T) 함수를 코드레벨에서 사용이 가능하여, LiveData

객체 안에 저장된 값을 수정할 필요가 있을 때 사용해야 합니다.

일반적으로 MutableLiveData은 ViewModel 안에서 사용됩니다.

 

관찰자 관계가 설정이되면 , LiveData 값을 업데이트 할 수 있습니다.예시) 버튼을 클릭하면 모든 관찰자에게 변경에 대해 트리거 함

button.setOnClickListener {
    val anotherName = "John Doe"
    model.currentName.setValue(anotherName)
}

위의 예제에서 setValue()를 호출하게 되면, "John Doe"와 같이 onChanged() 함수가 관찰자에게 호출됩니다.
즉, 버튼을 누르는 상황에서 setValue()나 postValue()를 호출하여 여러 이유(네트워크 요청, 데이터베이스 로드 등)에 의해 관찰자를 트리거하고 UI를 업데이트할 수 있음을 보여줍니다.
** 메인 스레드에서 LiveData를 업데이트하려면 setValue(T)를 호출해야합니다.코드가 워커 스레드에서 작성하려면 LiveData 객체를 업데이트하는 대신에 postVaule(T)를 사용할 수 있습니다.

 

Room과 연계에서 LiveData 사용

Room 데이터베이스는 LiveData 객체를 리턴하는 쿼리를 제공합니다. (DAO (Database Access Object))

Room 데이터베이스는 데이터베이스가 업데이트 되면, LiveData 객체에 업데이트하기위해 필요한 모든 코드를 생성합니다.

생성된 코드는 백그라운드에서 비동기적으로 실행됩니다.

이러한 패턴은 데이터베이스에 저장된 데이터를 UI에 출력하기에 유용합니다.

 

Coroutine과 연계에서 LiveData 사용

LiveData는 Kotlin coroutine을 지원합니다.

 

다음 포스팅에 추가로 작성하도록 하겠습니다.

반응형

'DEV > Android' 카테고리의 다른 글

[Android] Jetpack - Navigation 1  (0) 2023.04.10
[Android] Jetpack - LiveData - 2  (4) 2023.03.29
[Android] Jetpack - Lifecycle - 2  (0) 2023.03.21
[Android] Jetpack - Lifecycle - 1  (0) 2023.03.21
[Android] Jetpack - Data Binding - 3  (0) 2023.03.15