Jetpack Compose 의 collectAsState()
와 collectAsStateWithLifecycle()
두 API 에 대해 알아봅시다.
두 API 는 모두 flow 데이터를 수집하여 Compose UI state 로 변환할 때 사용하는 composable 함수입니다.
그렇다면 두 API 는 어떤 차이점이 있고, 어떤 상황에서 사용되어야 할까요?
collectAsState()
는 Composition
의 라이프사이클을 따라갑니다.
Enter the Composition(최초 Composable 함수 호출) 단계에서 flow 데이터가 수집되기 시작하고, Leave the Composition(Composable 함수 제거) 단계에서 flow 데이터 수집을 중단합니다.
collectAsStateWithLifecycle() 은 안드로이드 앱의 라이프사이클을 따라갑니다.
따라서 Lifecycle.State.STARTED
상태일 때 데이터를 수집하기 시작하고, Lifecycle.State.STARTED
상태가 아닐 때 데이터 수집을 중단합니다.
예제 코드를 통해 collectAsState()
와 collectAsStateWithLifecycle()
의 차이를 알아봅시다.
class MainViewModel: ViewModel() {
private val _cnt: MutableStateFlow<Int> = MutableStateFlow(0)
val cnt: StateFlow<Int> get() = _cnt.asStateFlow()
init {
test()
}
private fun test() {
viewModelScope.launch {
for (i in 1 .. 20) {
delay(1000L)
_cnt.value = i
}
}
}
}
MainViewModel.kt
클래스에 cnt
라는 StateFlow
변수가 존재합니다.
test()
함수에서 1초마다 cnt
변수를 1씩 증가합니다.
class MainActivity : ComponentActivity() {
private val mainViewModel: MainViewModel = MainViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val test1 by mainViewModel.cnt.collectAsState()
val test2 by mainViewModel.cnt.collectAsStateWithLifecycle()
WeatherTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
Greeting(name = "test1(collectAsState): $test1")
Greeting(name = "test2(collectAsStateWithLifecycle): $test2")
}
}
}
}
}
override fun onResume() {
super.onResume()
Log.d("[TEST] KEH", "=========================== onResume ===========================")
}
override fun onStop() {
super.onStop()
Log.d("[TEST] KEH", "=========================== onStop ===========================")
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Log.d("[TEST] KEH", "name: $name")
Text(
text = "Hello $name!",
modifier = modifier
)
}
MainActivity.kt
에서 test1
변수와 test2
변수는 MainViewModel
의 cnt
변수를 수집합니다.
단, test1
은 collectAsState()
방식으로, test2
는 collectAsStateWithLifecycle()
방식으로 수집합니다.
그리고 test1
과 test2
는 Greeting()
컴포저블 함수를 통해 텍스트로 화면에 표출됩니다.
onResume
과 onStop
에서 로깅을 한 이유는 onStart
와 onPause
시점보다 두 방식의 차이를 더 명확하게 확인할 수 있기 때문입니다.
로깅 결과를 확인해보면 아래와 같습니다.
=========================== onResume ===========================
test1(collectAsState): 0
test2(collectAsStateWithLifecycle): 0
test1(collectAsState): 1
test2(collectAsStateWithLifecycle): 1
test1(collectAsState): 2
test2(collectAsStateWithLifecycle): 2
test1(collectAsState): 3
test2(collectAsStateWithLifecycle): 3
test1(collectAsState): 4
test2(collectAsStateWithLifecycle): 4
test1(collectAsState): 5
test2(collectAsStateWithLifecycle): 5
test1(collectAsState): 6
test2(collectAsStateWithLifecycle): 6
test1(collectAsState): 7
test2(collectAsStateWithLifecycle): 7
test1(collectAsState): 8
test2(collectAsStateWithLifecycle): 8
=========================== onStop ===========================
test1(collectAsState): 9
test1(collectAsState): 10
test1(collectAsState): 11
test1(collectAsState): 12
test1(collectAsState): 13
test1(collectAsState): 14
test1(collectAsState): 15
=========================== onResume ===========================
test2(collectAsStateWithLifecycle): 15
test1(collectAsState): 16
test2(collectAsStateWithLifecycle): 16
test1(collectAsState): 17
test2(collectAsStateWithLifecycle): 17
test1(collectAsState): 18
test2(collectAsStateWithLifecycle): 18
test1(collectAsState): 19
test2(collectAsStateWithLifecycle): 19
test1(collectAsState): 20
test2(collectAsStateWithLifecycle): 20
처음 onResume
상태에서는 test1
과 test2
모두 정상적으로 데이터를 수집합니다.
onPause
상태가 되자 앱 라이프사이클을 인식하는 test2
는 데이터 수집을 중단하고, test1
만 데이터를 수집합니다.
다시 onResume
상태로 돌아오면 test2
는 데이터 수집을 재시작하여 test1
, test2
변수 데이터를 수집하는 것을 확인할 수 있습니다.
1. collectAsState()
방식은 Composition
라이프사이클을 따라 데이터 수집을 시작 및 중단합니다.
2. collectAsStateWithLifecycle()
방식은 앱 라이픗사이클을 따라 데이터 수집을 시작 및 중단합니다.
3. 안드로이드 앱에서 라이프사이클에 따라 데이터 상태 관리는 굉장히 중요합니다. 만약 collectAsState()
방식을 사용하여 데이터를 수집한다면 백그라운드 상태에서도 계속 데이터가 수집될 것이고, 보이고 있지 않은 UI 를 계속 리컴포지션하게 됩니다. 이는 휴대폰의 배터리 소모량을 늘리는 원인이 됩니다.
4. 따라서 안드로이드 앱을 개발할 때에는 collectAsStateWithLifecycle()
방식이 권장됩니다.
5. 안드로이드 앱 이외에 다른 플랫폼을 개발할 때에는 앱의 라이프사이클을 고려할 필요가 없으므로 collectAsState()
방식이 사용됩니다.
궁금한 점이나 잘못된 내용이 있을 경우 댓글 부탁드립니다.
읽어주셔서 감사합니다 :)