嗨,由于@composable invocations can only happen from the context of an @composable function
,我目前在Jetpack Compose
中的导航方面遇到了困难。我有一个功能:
private fun signInResult(result: FirebaseAuthUIAuthenticationResult) {
val response = result.idpResponse
if (result.resultCode == RESULT_OK) {
user = FirebaseAuth.getInstance().currentUser
Log.e("MainActivity.kt", "Innlogging vellykket")
ScreenMain()
} else {
Log.e("MainActivity.kt", "Feil med innlogging" + response?.error?.errorCode)
}
}
并与下面显示的导航类一起使用,我只得到上面显示的错误消息,我该如何修复它?
@Composable
fun ScreenMain(){
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Routes.Vareliste.route) {
composable(Routes.SignUp.route) {
SignUp(navController = navController)
}
composable(Routes.ForgotPassword.route) { navBackStack ->
ForgotPassword(navController = navController)
}
composable(Routes.Vareliste.route) { navBackStack ->
Vareliste(navController = navController)
}
composable(Routes.Handlekurv.route) { navBackStack ->
Handlekurv(navController = navController)
}
composable(Routes.Profileromoss.route) { navBackStack ->
Profileromoss(navController = navController)
}
}
}
用完整的代码编辑如果你们想看的话,这是这个类的完整代码!
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetpackComposeDemoTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
LoginPage()
}
}
}
}
private var user: FirebaseUser? = FirebaseAuth.getInstance().currentUser
private lateinit var auth: FirebaseAuth
@Composable
fun LoginPage() {
Box(modifier = Modifier.fillMaxSize()) {
}
Column(
modifier = Modifier.padding(20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Velkommen til ITGuys", style = TextStyle(fontSize = 36.sp))
Spacer(modifier = Modifier.height(20.dp))
Box(modifier = Modifier.padding(40.dp, 0.dp, 40.dp, 0.dp)) {
Button(
onClick = { signIn() },
shape = RoundedCornerShape(50.dp),
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {
Text(text = "Logg inn")
}
}
}
}
private fun signIn() {
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build()
)
val signinIntent = AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build()
signInLauncher.launch(signinIntent)
}
private val signInLauncher = registerForActivityResult(
FirebaseAuthUIActivityResultContract()
) {
res -> this.signInResult(res)
}
private fun signInResult(result: FirebaseAuthUIAuthenticationResult) {
val response = result.idpResponse
if (result.resultCode == RESULT_OK) {
user = FirebaseAuth.getInstance().currentUser
Log.e("MainActivity.kt", "Innlogging vellykket")
ScreenMain()
} else {
Log.e("MainActivity.kt", "Feil med innlogging" + response?.error?.errorCode)
}
}
}
我需要添加更多的文本才能发布这么多代码,你可以忽略这些文本,因为它只是为了能够发布。
如@z.y所述,您可以通过onFirebaseAuthSuccess传递lambda。我还想补充一点,当你将navController传递到注册屏幕时,你需要传递的lambda回调应该看起来像
onFirebaseAuthSuccess = { navController.navigate(Routes.Profileromoss.route) } - or whatever route you need
基于
composable(Routes.SignUp.route) {
SignUp(navController = navController)
}
我假设您的signIn
屏幕是在可组合的范围内调用的。如果你能添加包含你如何调用signInResult
函数的代码摘录,我们可以肯定
我不熟悉Firebase Authentication
,所以我不确定您在哪里调用或如何使用signInResult
函数,但您不能从作用域调用一个用@Composable
(ScreenMain
(注释的函数,该函数未被其注释,例如ordinary
函数(signInResult
(。
您可以考虑为signInResult
添加一个lambda
回调,该回调将在RESULT_OK
条件块中调用。
private fun signInResult(result: FirebaseAuthUIAuthenticationResult, onFirebaseAuthSuccess: () -> Unit) {
val response = result.idpResponse
if (result.resultCode == RESULT_OK) {
...
...
onFirebaseAuthSuccess() // this callback
} else {
...
}
}
编辑:@sgtpotatoe有更好的答案,你可以从lambda callback
调用根目录中的navigation
,它将导航到你的目标屏幕。
好吧,在MainActivity中,您希望导航组件位于顶部:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetpackComposeDemoTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
ScreenMain()
}
}
}
}
然后为登录页面添加一条到导航主机的路线:
composable(Routes.LoginPage.route) {
LoginPage(navController = navController)
}
我认为这是一个重大的变化,但你必须依靠视图模型来进行身份验证,这样它就可以处理呼叫,而不会阻塞ui或显示加载屏幕,并与视图通信
它看起来像这样:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = MyViewModel()
setContent {
JetpackComposeDemoTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
ScreenMain(viewModel)
}
}
}
}
在LoginPage中,您希望访问视图模型以启动身份验证服务调用
在LoginPage中,您希望访问视图模型以观察调用是否成功,在这种情况下,请执行导航
在MyViewModel中,您希望进行身份验证调用,并在身份验证成功的情况下更新触发导航的变量
以下是compose中的一个示例firebase身份验证应用程序,我将使用它作为指南https://firebase.blog/posts/2022/05/adding-firebase-auth-to-jetpack-compose-app