본문 바로가기

[Android]/허접 Programming Tips

[Jetpack Compose] compose.foundation 업데이트에 따른 TextFieldState textAsFlow() -> snapshotFlow 마이그레이션

안녕하세요!

 

최근 9월 10일 Compose 업데이트가 되며 몇몇 Experimental 이었던 코드들이 정식(Stable) 적용되었습니다.

이에 따라, 그전 버전에서 잘 사용하던 코드들이 컴파일 에러가 발생하기 시작했습니다.

 

(물론 제가 부지런하게 업데이트 하지 않아서 몰랐을 테지만...)

 

(버전 정보)

https://developer.android.com/jetpack/androidx/releases/compose#versions

 

Compose  |  Jetpack  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Compose 모양과 데이터 종속 항목을 설명하는 구성 가능

developer.android.com

 

(무슨 iOS Swift를 경험하는 줄...)

 

[문제발생]

1) libs.versions.toml 파일에서 아래 composeBom 버전을 아래와 같이 설정 후 gradle sync를 하였습니다.

[versions]
# ...
composeBom = "2024.09.01"
# ...

2) 갑자기 아래와 같이 Build 에러가 우두두두 (240 errors) ??

 

[코드 분석]

설명: ViewModel 내에서 TextFieldState의 변화를 감지하기 위해 사용하던 코드입니다.

 

(AS-IS)

 

@HiltViewModel
class LoginViewModel
@Inject
constructor(
private val loginUseCase: LoginUseCase,
private val inputValidator: Inputvalidator
) : ViewModel() {
var state by mutableStateOf(value = LoginState())
private set
// ...
init {
combine(state.email.textAsFlow(), state.password.textAsFlow()) { email, password ->
val canLogin = inputValidator.isValidEmail(
email = email.toString().trim()
) && password.isNotEmpty()
state = state.copy(
canLogin = canLogin
)
}.launchIn(scope = viewModelScope)
}
// ...
}
data class LoginState(
val email: TextFieldState = TextFieldState(),
val password: TextFieldState = TextFieldState(),
val canLogin: Boolean = false,
)

- 기존에는 Experimental 이었던 "textAsFlow()"를 사용했었었습니다.

 

(TO-BE)

@HiltViewModel
class LoginViewModel
@Inject
constructor(
private val loginUseCase: LoginUseCase,
private val inputValidator: Inputvalidator
) : ViewModel() {
var state by mutableStateOf(value = LoginState())
private set
// ...
init {
combine(snapshotFlow { state.email.text },
snapshotFlow { state.password.text }) { email, password ->
val canLogin = inputValidator.isValidEmail(
email = email.toString().trim()
) && password.toString().isNotEmpty()
state = state.copy(
canLogin = canLogin
)
}.launchIn(scope = viewModelScope)
}
// ...
}
data class LoginState(
val email: TextFieldState = TextFieldState(),
val password: TextFieldState = TextFieldState(),
val canLogin: Boolean = false,
)

- 이제는 "snapshotFlow"를 사용하시면 됩니다.

- snapshotFlow { state.email.text } 형태로요! (아래 공식문서에 친절하게 설명이 잘 나와있습니다.)

링크: https://developer.android.com/reference/kotlin/androidx/compose/foundation/text/input/TextFieldState

 

그럼 오랜만에 짧은 Tip 남기고 떠납니다!

 

감사합니다~!