3 분 소요

이번 포스팅은 안드로이드 안드로이드 ACC 구성 요소중 하 나인 LiveData에 대해서 알게된 내용을 정리하려고 한다.😀 ViewModel을 사용하여 간단한 화폐 변환을 하는 예제에 LiveData 를 추가하여 좀 더 개선해 보려고 한다.


LiveData 핵심 요약

LiveData 는 관찰 가능한(obserable) 데이터 홀더 클래스 이다. LiveData 의 인스턴스에 포함된 데이터는 앱의 다른 객체 들이(Activity나 Fragment와 같은 UI 컨트롤러) 관찰할 수 있다. 또한 LiveData는 활동 생명 주기 상태 를 인식하여 앱의 메모리 누수 의 발생을 줄여준다.

Observer 클래스를 사용하여 실시간으로 데이터가 변경 되는지 감시하고 있다가 UI 컨트롤러(Activity)에게 알려주고, 알림을 받은 UI 컨트롤러는 데이터를 이용하여 UI를 업데이트한다.😮

여기서 Observer가 관찰하는 데이터는 LiveData라는 데이터 홀더 클래스를 가지고 있는 데이터만 감시를 하게된다.

LiveData 는 LifeCycleOwner가 기본적으로 구현되어 있는 Activity와 Fragment에서 getLifecycle() 함수를 통하여 생명 주기를 가져와 활성화된 상태 에서만 변경사항을 알림을 받아 앞서 언급한 메모리 누수 의 발생을 줄여줄 수 있는것이다.👌

Observer 클래스로 표현되는 관찰자 의 수명주기가 STARTED 또는 RESUMED 상태일때 활성화(수신) ⭕

수명주기가 끝나는 순간 관찰자비 활성화(수신 거부)❌
Lifecycle 객체의 상태가 DESTROYED로 변경되면 관찰자를 삭제 가 가능.

LiveData의 사용의 장점

  • 데이터 상태와 UI의 일치 보장
    • LiveData는 데이터의 변경시 Observer 객체에 알린다. 따라서 Observer가 대신 UI를 업데이트하여 데이터와 UI의 일치를 보장 한다.
  • 메모리 누수 없음
    • Observer는 UI 컨트롤러(Activity/Fragment)의 수명 주기(Lifecycle) 객체에 결합이 되어있으므로 수명 주기가 끝나면 자동으로 삭제된다.
  • 중지된 활동으로 인한 비정상 종료 없음
    • Oberver의 수명 주기가 비활성 상태 에 있으면 어떤 LiveData의 이벤트를 수신하지 않기 때문에 비정상 종료가 없다.
  • 수명 주기의 자동화
    • UI 구성 요소는 데이터를 관찰 만 하기 때문에 관찰을 중지나 다시시작을 하지 않는다. 따라서 LiveData데이터를 관찰하는 동안 관련 수명 주기 상태의 변경을 인식하여 자동으로 관리한다.
  • 최신 데이터 유지
    • 수명 주기가 비활성화에서 활성화가 될때는 최신의 데이트를 수신한다.
  • 적절한 구성 변경
    • 기기의 회전이 일어나면 기존에는 savedInstanceState 를 통하여 데이터를 저장하였다고 복원하는 방식이였지만 LiveData를 사용하면 최신의 데이터를 즉시 받을 수 있다.
  • 리소스 공유
    • LiveData 객체가 한번 시스템 서비스에 연결되면 리소스가 필요한 모든 관찰자(Observer)가 LiveData 객체를 볼 수 있다.

ViewModel에 LiveData 추가하기

기존의 MainViewModel 클래스에 결과로 보여질 값을 LiveData의 사용으로 바꿔준다.
LiveData의 사용은 캡슐화 를 통하여 접근할 수 있게 해준다.

캡슐화💊: 객체의 변수와 함수를 하나로 묶고 실제 구현 내용 일부를 내부에 감추어 외부에서 쉽게 사용하지 못하도록 한다.

MutableLiveData vs LiveData

MutableLiveData는 변경이 가능하고 LiveData는 변경이 불가능 하다는 의미이다.

ViewModel의 관점에서 LiveData를 보게되면

  • ViewModel은 변경이 불가능한 LiveData 객체만 외부 관찰자에게 보여줘야한다.
    • -> View(외부)에서는 LiveData 데이터를 변경하지 못해야 한다.
  • LiveData를 사용하면 실시간으로 데이터가 변경 을 관찰해야 하지만 변경이 불가능하면 이것 또한 모순이다😂

📍 따라서 public 으로 LiveData을 만들고 private 으로 MutableLiveData를 선언하여 외부에서는 관찰만 하고, 내부에서는 수정을 하는 방식으로 사용을 하게된다.

LiveData을 변경을 할때는 MutableLiveData의 사용 말고도 다음의 방법이 있다.

  • Room 등의 라이브러리를 사용한다면 Room의 데이터가 바뀌면 해당 LiveData로 바뀐 Data를 즉시 수정해준다.
  • Room 등의 사용이 없다면 viewModel에서 MutableLiveData를 생성하여 LiveData와 연결 을 하고, 데이터의 변경은 MutableLiveData를 사용 한다.
// Room 등의 라이브러리를 사용하여 데이터를 직접 할당
val livedata : LiveData<Float> = repository.함수이름

// MutableLiveData를 사용하여 직접 데이터를 가공하여 사용
private val _livedata : MutableLiveData<Float> = MutableLiveData()
val livedata: LiveData<Float> get() = _livedata

1. LiveData 추가

앞서 설명한 LiveDataMainViewModel 클래스에 선언해준다.

class MainViewModel: ViewModel() {
    private val usd_to_eu_rate = 0.74f
    private var dollarText = ""
    private var _result: MutableLiveData<Float> = MutableLiveData()
    val result: LiveData<Float> get() = _result

    fun setAmount(value: String) {
        this.dollarText = value
        _result.value = value.toFloat() * usd_to_eu_rate
    }
}

2. Observer 객체 생성

LiveData를 선언하였다면 Observer 인터페이스를 구현하는 객체를 생성하여 LiveData의 데이터 변경을 관찰할 수 있다.

일반적으로는 UI 컨트롤러(Activity/Fragment)Observer 객체를 만든다. Observer 인터페이스는 LiveData의 데이터 값이 변경될때 호출되는 onChange() 함수를 구현하면 된다.

// 데이터 관찰을 위한 옵저버 설정 -> onChange() 함수의 구현
val resultObserver = Observer<Float> { result ->
    binding.resultText.text = result.toString()
}

3. observe() 함수 호출

observe() 함수를 사용하여 LiveData 객체와 Observer 객체를 연결합니다. observe() 메서드는 LifecycleOwner 객체와 Observer 객체 를 파라미터로 받는다.

// viewModel를 Observer와 연결
viewModel.result.observe(this, resultObserver)

이렇게 하면 ViewModel과 Observer 객체가 연결 이되고 Observer 객체는 LiveData 객체를 (여기선 변수 result)를 구독 하여 데이터의 변경사항에 대한 알림을 받는다.

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        // 데이터 관찰을 위한 옵저버 설정
        val resultObserver = Observer<Float> { result ->
            binding.resultText.text = result.toString()
        }
        // viewModel를 Observer와 연결
        viewModel.result.observe(this, resultObserver)

        with(binding) {
            convertButton.setOnClickListener {
                if (dollarText.text.isNotEmpty()) {
                    viewModel.setAmount(dollarText.text.toString())
                } else {
                    resultText.text = "No Value"
                }
            }
        }
    }
}

LiveData를 사용하여 실시간으로 데이터의 변경을 감지하도록 개선해 보았다. 다음에는 DataBindingLiveData와 같이 사용해보면서 DataBinding을 알아보도록 하겠다.

📍DataBinding + LiveData 적용하기


References

맨 위로 이동 ↑

댓글남기기