깨알 개념/Android

[Android] LiveData - Flow로 마이그레이션

interfacer_han 2024. 8. 29. 20:17

#1 이전 글

 

[Kotlin] Coroutines Flow - StateFlow

#1 개요 StateFlowA SharedFlow that represents a read-only state with a single updatable data value that emits updates to the value to its collectors. A state flow is a hot flow because its active instance exists independently of the presence of collecto

kenel.tistory.com

StateFlow에 대해 다룬 이전 글에서 이어진다. LiveData가 쓰인 XML 기반 View 프로젝트를 수정해, LiveData를 StateFlow로 마이그레이션해본다.

 

#2 수정할 샘플 앱

 

[Android] LiveData - 기초

#1 개요#1-1 LiveData LiveData 개요  |  Android 개발자  |  Android DevelopersLiveData를 사용하여 수명 주기를 인식하는 방식으로 데이터를 처리합니다.developer.android.comLiveData. 문서적인 정의는 Data의 변경을

kenel.tistory.com

위 게시글의 완성된 앱을 일부 수정해서 LiveData를 Flow로 마이그레이션시켜본다.

 

#3 간단한 마이그레이션 - MainActivityViewModel 수정

package com.example.implicitobservation

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.flow.MutableStateFlow

class MainActivityViewModel : ViewModel() {
    private var count: MutableStateFlow<Int> = MutableStateFlow(0)

    fun getCurrentCount(): LiveData<Int> {
        return count.asLiveData()
    }

    fun updateCount() {
        count.value++
    }
}

안드로이드 프로젝트에서 이미 LiveData를 광범위하게 사용하고 있기에, 일관성을 위해 LiveData를 유지하고 싶을 수 있다. 이 경우 아주 간단한 방식으로 마이그레이션을 할 수 있다. 바로 원래 LiveData이던 프로퍼티를 StateFlow로 바꾸고, 해당 프로퍼티의 Getter에는 asLiveData() 확장함수를 사용하는 것이다. 이러면 전체 프로젝트를 수정하지 않아도 되면서, 동시에 LiveData 대비 StateFlow의 비교 우위적 성능을 누릴 수 있다 (#1에 있는 이전글의 #4 참조). 이는 구글 공식 문서에서도, 비동기 데이터 스트림을 LiveData로 표현하고자하는 경우 권장하는 방식이다.

 

#4 통째로 마이그레이션

#4-1 MainActivityViewModel 수정

package com.example.livedatabasics

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class MainActivityViewModel : ViewModel() {
    private var count: MutableStateFlow<Int> = MutableStateFlow(0)

    fun getCurrentCount(): StateFlow<Int> {
        return count
    }

    fun updateCount() {
        count.value++
    }
}

Getter에 asLiveData()를 사용하지 않는다. 때문에, count 프로퍼티를 참조하는 코드의 수정이 필요하다.

 

#4-2 MainActivity 수정

package com.example.livedatabasics

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.example.livedatabasics.databinding.ActivityMainBinding
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: MainActivityViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

/*
        viewModel.getCurrentCount().observe(this, Observer {
            binding.countText.text = it.toString()
        })
*/
        lifecycleScope.launch {
            viewModel.getCurrentCount().collect {
                binding.countText.text = it.toString()
            }
        }

        ...
    }
}

count는 더 이상 LiveData가 아니기 때문에, LiveData.observe()를 사용할 수 없다. 해당 코드를 삭제하고, Flow.collect()를 사용한다. collect()는 suspend가 붙는 비동기 함수이므로 CoroutineScope 내에 위치해야 한다. MainActivity는 LifecycleOwner이므로 CoroutineScope로서 (자원 효율성 증대를 위해) LifecycleScope를 사용한다.

 

#5 작동 확인

#2의 완성된 앱과 같이, 잘 작동한다.

 

#6 완성된 앱

 

android-practice/live-data/MigrationToFlow at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com