如何在可组合的屏幕中使用协同程序?



我正在使用jetpack Compose和flow,我得到一个错误,试图获得与LaunchedEffect可组合屏幕内的数据

@Composable的调用只能在@Composable函数的上下文中发生

这里我详细说明了我的代码流程

这里它在LaunchedEffect

中产生错误屏幕

@Composable
fun LoginScreen(
navController: NavController,
viewModel: LoginViewModel = hiltViewModel()
) {

Box(
modifier = Modifier.fillMaxSize().fillMaxHeight()
) {
Column(
modifier = Modifier.fillMaxWidth().padding(15.dp),
) {
//TextField username
//TextField password

Button(
onClick = {
// Error  
// @Composable invocations can only happen from the context of a @Composable function
LaunchedEffect(Unit) {
viewModel.login(
viewModel.passwordValue.value, viewModel.usernameValue.value
)
}
},

) {
Text(text = stringResource(id = R.string.login))
}
}
}
}
ViewModel h5> API h5>
class ToLogin @Inject constructor(private val apiAuth: AuthApiSource) {
operator fun invoke(username: String, password: String): Flow<Result<AccessToken?>> =
flow {
val response = runCatching {
val token = apiAuth.login(username, password)
token.getOrThrow()
}
emit(response)
}
}

正确的做法是什么?

你必须使用rememberCoroutineScope:

@Composable
fun LoginScreen(
navController: NavController,
viewModel: LoginViewModel = hiltViewModel()
) {
val scope = rememberCoroutineScope()
Box(
modifier = Modifier.fillMaxSize().fillMaxHeight()
) {
Column(
modifier = Modifier.fillMaxWidth().padding(15.dp),
) {
//TextField username
//TextField password
Button(
onClick = {
// Error  
// @Composable invocations can only happen from the context of a @Composable function
scope.launch {
viewModel.login(
viewModel.passwordValue.value, viewModel.usernameValue.value
)
}
},
) {
Text(text = stringResource(id = R.string.login))
}
}
}
}

作为Francesc回答的补充,您可以将viewModel的方法作为参数传递,如:

@Composable
fun LoginScreen(
navController: NavController,
clickButtonCallback: () -> Unit
) {
Box(
modifier = Modifier.fillMaxSize().fillMaxHeight()
) {
Column(
modifier = Modifier.fillMaxWidth().padding(15.dp)
) {
//TextField username
//TextField password
Button(onClick = clickButtonCallback) {
Text(text = stringResource(id = R.string.login))
}
}
}
}

并在调用可组合方法时使用:

val scope = rememberCoroutineScope()
val viewModel: LoginViewModel = hiltViewModel()
LoginScreen(
navController = navController,
clickButtonCallback = {
scope.launch {
viewModel.getNewSessionToken()
}
}
)

这样做,你的ViewModel只创建一次,因为可组合方法有时被Android系统调用多次。

相关内容

  • 没有找到相关文章

最新更新