简体   繁体   English

如何解决由 state 在 android 中更改导致的无限循环与 firebase 认证组合

[英]How to resolve infinite loop causing by state change in android compose with firebase authentication

I have an application with sign in via email and password with firebase.我有一个应用程序,通过 email 登录,密码为 firebase。 I'm using jetpack compose with MVVM and clean architecture.我正在使用带有 MVVM 和干净架构的 jetpack compose。

When getting from firebase that login was done I'm getting true in the view model and then listening to this state change in the composable.当从 firebase 获取登录已完成时,我在视图 model 中得到了正确的结果,然后在可组合物中收听此 state 更改。

The problem is I'm always get in the when statement of the sign in state and it cause an infinite loop that always navigating to the next composable.问题是我总是在 state 中出现符号的 when 语句,它会导致一个无限循环,总是导航到下一个可组合。

Copying here the specific line from the view:在此处复制视图中的特定行:

when (val response = viewModel.signInState.value) {
        is Response.Loading -> LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
        is Response.Success -> if (response.data) {
            navController?.navigate(Screen.HomeScreen.route)
        }
        is Response.Error -> LaunchedEffect(Unit) {
            scaffoldState.snackbarHostState.showSnackbar("Error signing out. ${response.message}", "", SnackbarDuration.Short)
        }
    }

My View:我的观点:

@Composable
fun LoginScreen(
    navController: NavController?,
    viewModel: LoginViewModel = hiltViewModel()
) {
    val scaffoldState = rememberScaffoldState()
    Scaffold(scaffoldState = scaffoldState) {
        Column (
            modifier = Modifier
                .fillMaxHeight()
                .background(
                    Color.White
                ),
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally,
        ){
            var email = viewModel.email
            var pass = viewModel.password
            var passwordVisibility = viewModel.passwordVisibility
            TitleView(title = "SIGN IN", topImage = Icons.Filled.Person, modifier = Modifier)
            Spacer(modifier = Modifier.padding(20.dp))
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Top
            ) {
                OutlinedTextField(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 20.dp),
                    value = email.value,
                    onValueChange = viewModel::setEmail,
                    label = { Text( "Email")},
                    placeholder = { Text("Password") }
                )
                OutlinedTextField(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 20.dp),
                    value = pass.value,
                    onValueChange = viewModel::setPassword,
                    label = { Text( "Password")},
                    placeholder = { Text("Password") },
                    visualTransformation = if (passwordVisibility.value) VisualTransformation.None else PasswordVisualTransformation(),
                    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
                    trailingIcon = {
                        val image = if (passwordVisibility.value)
                            Icons.Filled.Visibility
                        else Icons.Filled.VisibilityOff

                        IconButton(onClick = {
                            viewModel.setPasswordVisibility(!passwordVisibility.value)
                        }) {
                            Icon(imageVector  = image, "")
                        }
                    }
                )
                Spacer(modifier = Modifier.padding(5.dp))
                Button(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 20.dp)
                        .border(
                            width = 2.dp,
                            brush = SolidColor(Color.Yellow),
                            shape = RoundedCornerShape(size = 10.dp)
                        ),
                    onClick = {
                        viewModel.signInWithEmailAndPassword()
                    },
                    colors = ButtonDefaults.buttonColors(
                        backgroundColor = Color.White
                    )
                ) {
                    Text(
                        text = "SIGN IN",
                        textAlign = TextAlign.Center,
                        fontSize = 20.sp,
                        style = TextStyle(
                            fontWeight = FontWeight.Thin
                        )
                    )
                }
                Spacer(modifier = Modifier.padding(5.dp))
                Button(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 20.dp)
                        .border(
                            width = 2.dp,
                            brush = SolidColor(Color.Yellow),
                            shape = RoundedCornerShape(size = 10.dp)
                        ),
                    onClick = {
                        viewModel.forgotPassword()
                    },
                    colors = ButtonDefaults.buttonColors(
                        backgroundColor = Color.White
                    )
                ) {
                    Text(
                        text = "FORGOT PASSWORD",
                        textAlign = TextAlign.Center,
                        fontSize = 20.sp,
                        style = TextStyle(
                            fontWeight = FontWeight.Thin
                        )
                    )
                }
            }
        }
    }

    when (val response = viewModel.signInState.value) {
        is Response.Loading -> LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
        is Response.Success -> if (response.data) {
            navController?.navigate(Screen.HomeScreen.route)
        }
        is Response.Error -> LaunchedEffect(Unit) {
            scaffoldState.snackbarHostState.showSnackbar("Error signing out. ${response.message}", "", SnackbarDuration.Short)
        }
    }

    when (val response = viewModel.forgotState.value) {
        is Response.Loading -> LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
        is Response.Success -> if (response.data) {
            LaunchedEffect(Unit){
                scaffoldState.snackbarHostState.showSnackbar("Please click the link in the verification email sent to you", "", SnackbarDuration.Short)
            }
        }
        is Response.Error -> LaunchedEffect(Unit){
            scaffoldState.snackbarHostState.showSnackbar("Error signing out. ${response.message}", "", SnackbarDuration.Short)
        }
    }
}

My View model:我的看法 model:

@HiltViewModel
class LoginViewModel @Inject constructor(
    private val useCases: UseCases
) : ViewModel() {
    private val _signInState = mutableStateOf<Response<Boolean>>(Response.Success(false))
    val signInState: State<Response<Boolean>> = _signInState

    private val _forgotState = mutableStateOf<Response<Boolean>>(Response.Success(false))
    val forgotState: State<Response<Boolean>> = _forgotState

    private val _email = mutableStateOf("")
    val email = _email
    fun setEmail(email: String) {
        _email.value = email
    }

    private val _password = mutableStateOf("")
    val password = _password
    fun setPassword(password: String) {
        _password.value = password
    }

    private val _passwordVisibility = mutableStateOf(false)
    val passwordVisibility = _passwordVisibility
    fun setPasswordVisibility(passwordVisibility: Boolean) {
        _passwordVisibility.value = passwordVisibility
    }

    fun signInWithEmailAndPassword() {
        viewModelScope.launch {
            useCases.signInWithEmailAndPassword(_email.value, _password.value).collect { response ->
                _signInState.value = response
            }
        }
    }

    fun forgotPassword() {
        viewModelScope.launch {
            useCases.forgotPassword(_email.value).collect { response ->
                _forgotState.value = response
            }
        }
    }
}

My Sign in function:我的登录 function:

override suspend fun signInWithEmailAndPassword(
        email: String,
        password: String
    ) = flow {
        try {
            emit(Response.Loading)
            val result = auth.signInWithEmailAndPassword(email, password).await()
            if (result.user != null)
                emit(Response.Success(true))
            else
                emit(Response.Success(false))
        } catch (e: Exception) {
            emit(Response.Error(e.message ?: ERROR_MESSAGE))
        }
    }

Navigation is also a side effect , after each frame of the animation you will again navigate to your destination.导航也是一个副作用,在 animation 的每一帧之后,您将再次导航到您的目的地。 Change your block to:将您的块更改为:

when (val response = viewModel.signInState.value) {
    is Response.Loading -> LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
    is Response.Success -> if (response.data) LaunchedEffect(response.data){ navController?.navigate(Screen.HomeScreen.route) }
    is Response.Error -> LaunchedEffect(Unit) {
        scaffoldState.snackbarHostState.showSnackbar("Error signing out. ${response.message}", "", SnackbarDuration.Short)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在删除导致无限循环的对象时修复基于Android的Firebase错误? - How to fix android based Firebase error while deleting objects causing an infinite loop? Firebase身份验证导致Android致命异常 - Firebase Authentication causing Android fatal exception 如何根据 android 中的 firebase 认证 state 执行条件导航 - How to perform conditional navigation depending on firebase authentication state in android state 更改的触发事件,在 android 喷气背包中组成 - Trigger event on state change, in android jetpack compose Android:在onCreate中启动一个intent会导致无限循环/崩溃 - Android: Starting an intent inside of onCreate is causing an infinite loop / crash 如何在 Android 的 Firebase 身份验证中更改登录电话号码? - How to change the Signed in Phone Number in Firebase Authentication for Android? 如何在特定用户android的Firebase身份验证上更改电子邮件ID - How to change email id on Firebase Authentication of a particular user android 如何在Android中进行无限循环? - how to make infinite loop in android? OnResume() 在 MainActivity 中导致无限循环 - OnResume() causing infinite loop in MainActivity setState() 在 flutter 中导致无限循环 - setState() causing infinite loop in flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM