Android 개발에서 데이터의 변경을 감지하고 이에 따라 UI를 업데이트하는 것은 매우 중요합니다. 이를 위해 다양한 관찰 가능한 데이터 홀더 클래스가 존재하며, 그중에서도 LiveData는 매우 유용한 도구입니다. 이번 글에서는 LiveData의 장점과 특별한 기능, 그리고 실제 사용 예제를 통해 이를 사용하는 상황을 알아보겠습니다.
LiveData란 무엇인가?
LiveData는 Android Architecture Components(AAC)의 일부로, 관찰 가능한 데이터 홀더 클래스입니다. 데이터의 변경을 감지하고, 이를 통해 로직을 수행할 수 있게 합니다. 최근에는 LiveData 외에도 Flow와 같은 관찰 가능한 데이터 홀더들이 있지만, LiveData만의 특별한 장점이 있습니다. Android에서 관찰 가능한 데이터 홀더를 사용할 때 가장 중요한 점 중 하나는 라이프사이클을 고려하는 것입니다. 액티비티나 프래그먼트가 활성화되어 있지 않은 상태에서 데이터 변경을 감지하면 메모리 누수나 크래시가 발생할 수 있습니다. LiveData는 이러한 문제를 해결하기 위해 설계되었습니다. LiveData를 관찰할 때는 LifecycleOwner를 명시적으로 전달해야 하며, 이는 액티비티나 프래그먼트의 라이프사이클을 관리하여 중지되거나 파괴될 경우 자동으로 옵저버를 중지하거나 제거할 수 있습니다. LiveData는 다시 관찰되더라도 항상 최신 데이터를 전달합니다. 이는 복잡한 상태 관리 없이 최신 데이터를 쉽게 얻을 수 있게 해 줍니다.
이론적으로 LiveData가 어떤 것인지 알아보았으니 코드를 보며 사용방법을 알아봅시다
LiveData를 사용하려면 Observer를 구현해야 합니다. Observer는 onChanged라는 단 하나의 메서드를 가지고 있으며, LiveData에서 데이터 변경이 발생할 때 호출됩니다. LifecycleOwner와 함께 등록된 Observer는 LiveData에서 생명주기의 상태에 맞춰 값을 전달받습니다.
class CounterViewModel : ViewModel() {
private val _count = MutableLiveData<Int>()
val count: LiveData<Int>
get() = _count
init {
_count.value = 0
}
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
fun decrement() {
_count.value = (_count.value ?: 0) - 1
}
}
class MainActivity : AppCompatActivity() {
private val counterViewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tvCount: TextView = findViewById(R.id.tvCount)
val btnIncrement: Button = findViewById(R.id.btnIncrement)
val btnDecrement: Button = findViewById(R.id.btnDecrement)
counterViewModel.count.observe(this, Observer { count ->
tvCount.text = count.toString()
})
btnIncrement.setOnClickListener {
counterViewModel.increment()
}
btnDecrement.setOnClickListener {
counterViewModel.decrement()
}
}
}
위 코드처럼 LiveData는 일반적으로 값은 외부에서 직접 변경할 수 없습니다. MutableLiveData의 경우 가변성을 줄 수 있는데, 다른 곳에서는 접근을 못하도록 private으로 설정하고 LiveData라는 MutableLiveData라는 값을 가져와서 해당 항목을 관찰하는 방법이 일반적인 사용방법입니다.
위코드는 value의 값을 바꿀 때 사용한 '='은 setValue를 의미합니다. MutableLiveData는 갑을 넣어줄 수 있는 2가지 메서드를 가지고 있는데 하나가 setValue고 또 다른 하나가 postValue입니다.
- setValue: UI 스레드에서 호출해야 합니다. 즉, 이 메서드는 항상 메인 스레드에서 실행되어야 합니다. 메인 스레드에서 실행되는 코드에서 사용하기에 적합합니다.
- postValue: 백그라운드 스레드에서 호출할 수 있습니다. 이 메서드는 값을 설정하고 나중에 메인 스레드에서 실행되도록 예약합니다. 주로 백그라운드 스레드에서 LiveData 값을 업데이트할 때 사용합니다.
ViewModel 말고 싱글톤으로 해당 데이터를 관리하고 싶다면 LiveData를 확장하여 커스텀 클래스를 만들 수 있습니다.
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager: StockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
value = price // 내부에서는 value의 값을 바꿀수있음
}
override fun onActive() { // LiveData 객체에 활성 옵저버가 있을 경우 호출
stockManager.requestPriceUpdates(listener)
}
override fun onInactive() { // LiveData 객체에 활성 옵저버가 없는 경우 호출
stockManager.removeUpdates(listener)
}
companion object {
private lateinit var sInstance: StockLiveData
@MainThread
fun get(symbol: String): StockLiveData {
sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
return sInstance
}
}
}
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
// Update the UI.
})
}
}
이런 식으로 싱글톤으로 데이터를 관리할 수도 있습니다.
참고
https://developer.android.com/topic/libraries/architecture/livedata?hl=ko
https://velog.io/@jjddww/AAC-LiveData
https://velog.io/@rootachieve/Android-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%8D%B0%EC%9D%B4%ED%84%B0
'안드로이드 > AAC(Android Architecture Components)' 카테고리의 다른 글
[AAC] Navigation의 정의와 적용 (0) | 2024.06.10 |
---|---|
[AAC] Lifecycle 정의와 활용 (0) | 2024.06.07 |
[AAC] DataBinding 고급 기능 (1) | 2024.06.05 |
[AAC] DataBinding의 정의와 적용 (0) | 2024.06.04 |
왜 앱개발자 공고 AAC사용 경험을 우대할까? (0) | 2024.06.03 |