개발일지

Android in A..Z - Lifecycle (LiveData) 본문

Android (안드로이드)/Lifecycle

Android in A..Z - Lifecycle (LiveData)

강태종 2021. 2. 6. 08:17

LiveData

LiveData는 Data를 Observer 패턴으로 관찰하여 변화가 있을 때 업데이트하는 코드를 작성할 수 있다. 일반적인 Observer패턴과 다르게 LiveData는 Activity나 Fragment의 생명주기를 관찰하여 활동 상태(STARTED, RESUMED)일 때만 업데이트한다.


dependency

dependencies {
    def lifecycle_version = "2.2.0"
    // LiveData
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
}

장점

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

Observer패턴을 따르기 때문에 Observer코드에 UI를 변경하는 코드를 삽입하면 데이터와 UI를 일치 시킬 수 있다.

메모리 누출 없음

Lifecycle을 관찰하여 수명 주기가 끝나면 자동으로 삭제된다.

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

비활성 상태일 때 어떠한 이벤트도 받지 않기 때문에 개발자가 Lifecycle을 처리하는 코드를 줄일 수 있다. ( 만약 Fragment가 Activity에서 detached된 상태에서는 Context를 가져올 수 없기 때문에 Context를 사용하는 코드를 실행하면 NPE가 발생할 수 있다. 하지만 LiveData는 비활성 상태에서 어떠한 이벤트도 수신하지 않기 때문에 이러한 실수를 줄일 수 있다.

최신 데이터 유지

비활성 상태에서 어떠한 이벤트도 수신하지 않다가 활성 상태로 돌아오면 최신의 데이터를 자동으로 업데이트합니다.


코드

보통 LiveData는 ViewModel과 같이 결합하여 사용한다. (ViewModel에서 수명주기와 독립하여 데이터를 저장하고 LiveData의 Observer 패턴으로 UI를 업데이트하는 편리함이 있기 때문에)

    private fun initViewModel() {
        with(model) {
            state.observe(this@MainActivity) {
                binding.state = it
                when(it ?: ChronometerViewModel.State.RESET) {
                    ChronometerViewModel.State.RUN -> {
                        binding.chronometer.start()
                    }
                    ChronometerViewModel.State.RESET -> {
                        binding.chronometer.stop()
                    }
                    ChronometerViewModel.State.STOP -> {
                        binding.chronometer.stop()
                    }
                    else -> {

                    }
                }
            }
        }
    }
    private fun onResetChronometer() {
        model.state.value = ChronometerViewModel.State.RESET
        model.sumOfTickTime = 0L
        binding.chronometer.base = SystemClock.elapsedRealtime()

        val count = model.recordList.size
        model.recordList.clear()
        recordAdapter.notifyItemRangeRemoved(0, count)
    }

    private fun onStartChronometer() {
        model.state.value = ChronometerViewModel.State.START

        val tickTime = SystemClock.elapsedRealtime()
        model.lastTickTime = tickTime
        binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime

        onRunChronometer()
    }

    private fun onRunChronometer() {
        model.state.value = ChronometerViewModel.State.RUN
    }

    private fun onResumeChronometer() {
        model.state.value = ChronometerViewModel.State.RESUME

        val tickTime = SystemClock.elapsedRealtime()
        model.lastTickTime = tickTime
        binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime

        onRunChronometer()
    }

    private fun onStopChronometer() {
        model.state.value = ChronometerViewModel.State.STOP
        binding.chronometer.base = SystemClock.elapsedRealtime() - model.sumOfTickTime
    }
  • observe() 메소드를 이용하여 LifecycleOwner와 Observer 객체를 넘겨주어 Observer를 등록할 수 있다.
  • observeForever() 메소드로 Observer 객체만 넘겨서 등록할 수 있다. ( 이 경우 항상 활성상태로 간주한다.)
  • removeObserver() 메소드로 등록된 Observer를 제거할 수 있다.
  • setValue() : Main Thread에서 LiveData의 값을 변경할 때 사용하는 코드 ( 즉각적으로 LiveData에게 이벤트를 전달한다. )
  • postValue() : Main Thread가 아닌 다른 Thread에서 LiveData의 값을 변경할 경우 ( Handler를 통해 적절한 시기에 Main Thread에 전달되고 값을 변경한다. )

Git (예제코드)

github.com/KangTaeJong98/Example/tree/main/Android/LifeCycle

 

KangTaeJong98/Example

My Example Code. Contribute to KangTaeJong98/Example development by creating an account on GitHub.

github.com

 

Comments