Android

[Android] Jetpack LiveData란?

728x90

 

 

LiveData란?

 LiveData는 데이터를 저장하고 변화를 관찰 할 수 있는 객체이다. UI객체는 LiveData에 옵저버를 등록할 수 있으며 데이터가 변경될 때 UI를 변경할 수 있다.

 예를 들어, 아래처럼 LiveData를 생성하고 옵저버를 등록할 수 있다. 데이터가 변경되면 옵저버에게 전달된다.

val elapsedTime = LiveData<Long>

elapsedTime.observe(this, Observer<Long> { time ->
    tv_timer.text = time.toString()
})

 LiveData는 LifecycleOwner의 상태가 STARTED와 RESUMED로 활성화 상태일 때만 옵저버에게 데이터 변화를 알려주고, DESTROYED로 변경되면 LiveData도 자동으로 소멸된다.

 LiveData는 ViewModel에서 사용되도록 설계가 되었다. 액티비티나 프래그먼트가 재실행되도 ViewModel은 소멸되지 않기 때문에 LiveData도 소멸되지 않는다. 따라서 메모리릭 등의 문제를 신경쓰지 않아도 된다.

 

 

LiveData 사용의 이점

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

 LiveData는 수명 주기 상태가 변경되면 Observer의 onChanged() 함수로 변경을 알린다. 변경이 발생할 때마다 Observer가 UI를 업데이트할 수 있다.

2. 메모리 누출 없음

 Observer는 Lifecycle과 결합해 있으며 연결된 수명 주기가 끝나면 자동으로 삭제된다.

3. 중지된 Activity로 인한 비정상 종료 없음

 Activity가 백 스택에 있을 때를 비롯하여 Observer의 수명 주기가 비활성 상태에 있으면 Observer는 어떠한 LiveData 이벤트도 받지 않는다.

4. 수명 주기를 더 이상 수동으로 처리할 필요 없음

 LiveData는 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하므로 이 모든 것을 자동으로 관리한다.

5. 항상 최신 데이터 유지

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

6. 적절한 구성 변경

 디바이스 회전과 같은 구성 변경으로 인해 Activity 또는 Fragment가 다시 생성되면, 사용 가능한 최신 데이터를 즉시 받게 된다.

7. 리소스 공유

 LiveData가 시스템 서비스에 한 번 연결되면 리소스가 필요한 모든 Observer는 LiveData를 바로 관찰할 수 있다.

 

 

LiveData 사용

1. LiveData 인스턴스를 만든다. 대개 ViewModel 클래스 내에서 진행된다.

2. onChanged() 메소드를 정의하는 Observer를 만든다. 이 메소드는 LiveData의 데이터가 변경될 때 발생하는 작업을 제어한다. 일반적으로 Activity나 Fragment와 같은 UI 컨트롤러에서 생성한다.

3. observe() 메소드를 사용하여 Observer를 LiveData에 연결한다. observe() 메소드는 LifecycleOwner를 가져온다. 일반적으로 Activity나 Fragment와 같은 UI 컨트롤러에서 Observer를 연결한다.

참고) observeForever(Observer) 메소드를 사용하면 연결된 LifecycleOwner 없이 Observer를 등록할 수 있다. 이 경우 Observer는 항상 활성 상태로 간주되므로 항상 수정 관련 알림을 받는다.

 

 

LiveData 예제

ViewModel과 LiveData

class LiveDataTimerViewModel : ViewModel() {
    private val initialTime: Long = SystemClock.elapsedRealtime()
    private val elapsedTime = MutableLiveData<Long>()
    
    fun getElapsedTime() = elapsedTime
    
    init {
        /* 1초마다 MutableLiveData.postValue로 현재 시간으로 변경한다. */
        Timer().scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                val newValue = (SystemClock.elapsedRealtime() - initialTime) / 1000
                elapsedTime.postValue(newValue)
            }
        }, 1000L, 1000L)
    }
}

 MutableLiveData는 LiveData를 상속하고 setValue()와 postValue()를 구현한 클래스이다.

  • setValue() : 데이터를 즉시 변경한다.
  • postValue() : Runnable로 데이터 변경을 요청한다. Main thread에서 Runnable이 실행될 때 데이터가 변경된다.

 

class MainActivity : AppCompatActivity() {
    private val liveDataTimerViewModel: LiveDataTimerViewModel by lazy {
        ViewModelProvider(this).get(LiveDataTimerViewModel::class.java)
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        liveDataTimerViewModel.getElapsedTime().observe(this, Observer<Long> { time ->
            chronometer.text = time.toString()
            Log.d("livedata", "Updating timer")
        })
    }
}

 

  • Observer를 통해 갱신된 시간을 UI에 출력해준다.
  • observe는 LifecycleOwner과 Observer를 인자로 받는다. 인자로 전달된 LifecycleOwner가 활성화 상태일 때만 LiveData는 데이터 변화를 옵저버에게 알려준다.
  • 액티비티의 상태가 STOPPED일 때 LiveData가 옵저버로 데이터 변화를 알려주지 않기 때문에 NullPointerException 등의 문제를 걱정할 필요는 없다.

 

 

LiveData 확장

 LiveData를 상속 받아 onActive와 onInactive를 오버라이딩 하여 확장시킬 수 있다. LiveData는 Lifecycle이 활성화일 때 onActive를 콜백해주고, 비활성화일 때 onInactive를 콜백해준다.

class MyTimerLiveData : LiveData<Long>() {
    private val initialTime: Long = SystemClock.elapsedRealtime()
    private val timer: Timer by lazy { Timer() }

    override fun onActive() {
        Log.d("MyTimerLiveData", "onActive")
        
        timer.scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                val newValue = (SystemClock.elapsedRealtime() - initialTime) / 1000
                postValue(newValue)
                Log.d("MyTimerLiveData", "updating real time")
            }
        }, 1000L, 1000L)
    }
    
    override fun onInactive() {
        Log.d("MyTimerLiveData", "onInactive")
        timer.cancel()
    }
}
class LiveDataTimerViewModel : ViewModel() {
    private val elapsedTime = MyTimerLiveData()
    
    fun getElapsedTime() = elapsedTime
}

 

 

observeForever, removeObserver

 Livecycle이 활성화 상태가 아니라도 옵저버가 데이터를 받고 싶으면 observeForever를 사용하면 된다. 옵저버를 제거할때는 removeObserver를 사용하면 된다.

liveDataTimerViewModel.getElapsedTime().observeForever(elapsedTimeObserver)

liveDataTimerViewModel.getElapsedTime().removeObserver(elapsedTimeObserver)

 

 

출처 : https://developer.android.com/topic/libraries/architecture/livedata

728x90