Androidjetpack compose 登录时如何移动屏幕?
In Android jetpack compose, how to move the screen when I log in?
MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var connectivityManager: ConnectivityManager
@Inject
lateinit var settingsDataStore: SettingsDataStore
override fun onStart() {
super.onStart()
connectivityManager.registerConnectionObserver(this)
}
override fun onDestroy() {
super.onDestroy()
connectivityManager.unregisterConnectionObserver(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screen.Login.route) {
composable(
route = Screen.Login.route
) { navBackStackEntry ->
val factory = HiltViewModelFactory(LocalContext.current, navBackStackEntry)
val viewModel: LoginViewModel = viewModel(key = "LoginViewModel", factory = factory)
LoginScreen(
isNetworkAvailable = connectivityManager.isNetworkAvailable.value,
onNavigateToHomeScreen = navController::navigate,
viewModel = viewModel
)
}
composable(
route = Screen.Home.route
) { navBackStackEntry ->
val factory = HiltViewModelFactory(LocalContext.current, navBackStackEntry)
val viewModel: HomeViewModel = viewModel(key = "HomeViewModel", factory = factory)
HomeScreen(
)
}
}
}
}
}
登录屏幕
@Composable
fun LoginScreen(
isNetworkAvailable: Boolean,
onNavigateToHomeScreen: (String) -> Unit,
viewModel: LoginViewModel
) {
val loading = viewModel.loading.value
val user = viewModel.user.value
Scaffold(
modifier = Modifier.fillMaxSize()
) {
if (!loading && user == null) {
Button(onClick = { viewModel.onTriggerEvent(LoginEvent.AuthStateEvent) }) {
Column(
) {
Text(text = "Log in")
}
}
}else {
user?.let {
val route = Screen.Home.route
onNavigateToHomeScreen(route)
}
}
}
}
LoginViewModel
@HiltViewModel
class LoginViewModel @Inject constructor(
private val postLogin: PostLogin,
private val connectivityManager: ConnectivityManager
) : ViewModel() {
val user: MutableState<User?> = mutableStateOf(null)
val loading = mutableStateOf(false)
val onLoad: MutableState<Boolean> = mutableStateOf(false)
fun onTriggerEvent(event: LoginEvent) {
viewModelScope.launch {
try {
when(event) {
is LoginEvent.AuthStateEvent -> {
Log.d(TAG,"Phase 1")
if (user.value == null) {
val auth: Auth = Auth([***AuthData***])
postAuth(auth)
}
}
}
}catch (e: Exception) {
Log.d(TAG, "launchJob: Exception: ${e}, ${e.cause}")
e.printStackTrace()
}
}
}
private fun postAuth(auth: Auth) {
Log.d(TAG,"Phase 2")
postLogin.execute(auth, connectivityManager.isNetworkAvailable.value).onEach { dataState ->
loading.value = dataState.loading
dataState.data?.let { data ->
user.value = data
Log.d(TAG,"Phase 3")
Log.d(TAG,"User Data File")
}
dataState.error?.let { error ->
Log.d(TAG, "postAuth: ${error}")
}
}.launchIn(viewModelScope)
}
}
登录事件
sealed class LoginEvent {
object AuthStateEvent: LoginEvent()
}
登录后
class PostLogin(
private val apiService: ApiService,
private val authDtoMapper: AuthDtoMapper,
private val userDtoMapper: UserDtoMapper
) {
fun execute(
auth: Auth,
isNetworkAvailable: Boolean
): Flow<DataState<User>> = flow {
//auth -> authDto -> InterActions -> userDto -> user
try {
emit(DataState.loading())
delay(1000)
if (isNetworkAvailable) {
val networkUser = postLoginFromNetwork(auth)
if (networkUser != null) {
emit(DataState.success(networkUser))
}else {
emit(DataState.error<User>("User data is null"))
}
}else {
emit(DataState.error<User>("Unable to connect network"))
}
}catch (e: Exception) {
emit(DataState.error<User>(e.message?: "Unknown Error"))
}
}
private suspend fun postLoginFromNetwork(auth: Auth): User {
return userDtoMapper.mapToDomainModel(apiService.login(authDtoMapper.fromDomain(auth)))
}
}
主屏幕
@Composable
fun HomeScreen() {
Card(
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "HomeScreen",
fontWeight = FontWeight.Bold,
fontSize = 40.sp
)
}
}
}
您好,我通过在 LoginScreen
上按 Login
按钮成功登录后将上面的代码转到 HomeScreen
。
确认沟通顺畅,也带来了价值
但是,当我尝试调试时,我确认这部分在登录屏幕上重复完成。
user?.let {
val route = Screen.Home.route
onNavigateToHomeScreen(route)
}
如您所见,当用户有一个值时,屏幕会移动,但那部分是重复完成的,所以 HomeScreen
屏幕像闪光一样闪烁。
这就是我问你这个问题的原因。沟通后数值改变时,请告诉我如何移动屏幕。
使用 LauchedEffect
LaunchedEffect(user){
user.let {
navController.navigate("")
}
}
MainActivity
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var connectivityManager: ConnectivityManager
@Inject
lateinit var settingsDataStore: SettingsDataStore
override fun onStart() {
super.onStart()
connectivityManager.registerConnectionObserver(this)
}
override fun onDestroy() {
super.onDestroy()
connectivityManager.unregisterConnectionObserver(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screen.Login.route) {
composable(
route = Screen.Login.route
) { navBackStackEntry ->
val factory = HiltViewModelFactory(LocalContext.current, navBackStackEntry)
val viewModel: LoginViewModel = viewModel(key = "LoginViewModel", factory = factory)
LoginScreen(
isNetworkAvailable = connectivityManager.isNetworkAvailable.value,
onNavigateToHomeScreen = navController::navigate,
viewModel = viewModel
)
}
composable(
route = Screen.Home.route
) { navBackStackEntry ->
val factory = HiltViewModelFactory(LocalContext.current, navBackStackEntry)
val viewModel: HomeViewModel = viewModel(key = "HomeViewModel", factory = factory)
HomeScreen(
)
}
}
}
}
}
登录屏幕
@Composable
fun LoginScreen(
isNetworkAvailable: Boolean,
onNavigateToHomeScreen: (String) -> Unit,
viewModel: LoginViewModel
) {
val loading = viewModel.loading.value
val user = viewModel.user.value
Scaffold(
modifier = Modifier.fillMaxSize()
) {
if (!loading && user == null) {
Button(onClick = { viewModel.onTriggerEvent(LoginEvent.AuthStateEvent) }) {
Column(
) {
Text(text = "Log in")
}
}
}else {
user?.let {
val route = Screen.Home.route
onNavigateToHomeScreen(route)
}
}
}
}
LoginViewModel
@HiltViewModel
class LoginViewModel @Inject constructor(
private val postLogin: PostLogin,
private val connectivityManager: ConnectivityManager
) : ViewModel() {
val user: MutableState<User?> = mutableStateOf(null)
val loading = mutableStateOf(false)
val onLoad: MutableState<Boolean> = mutableStateOf(false)
fun onTriggerEvent(event: LoginEvent) {
viewModelScope.launch {
try {
when(event) {
is LoginEvent.AuthStateEvent -> {
Log.d(TAG,"Phase 1")
if (user.value == null) {
val auth: Auth = Auth([***AuthData***])
postAuth(auth)
}
}
}
}catch (e: Exception) {
Log.d(TAG, "launchJob: Exception: ${e}, ${e.cause}")
e.printStackTrace()
}
}
}
private fun postAuth(auth: Auth) {
Log.d(TAG,"Phase 2")
postLogin.execute(auth, connectivityManager.isNetworkAvailable.value).onEach { dataState ->
loading.value = dataState.loading
dataState.data?.let { data ->
user.value = data
Log.d(TAG,"Phase 3")
Log.d(TAG,"User Data File")
}
dataState.error?.let { error ->
Log.d(TAG, "postAuth: ${error}")
}
}.launchIn(viewModelScope)
}
}
登录事件
sealed class LoginEvent {
object AuthStateEvent: LoginEvent()
}
登录后
class PostLogin(
private val apiService: ApiService,
private val authDtoMapper: AuthDtoMapper,
private val userDtoMapper: UserDtoMapper
) {
fun execute(
auth: Auth,
isNetworkAvailable: Boolean
): Flow<DataState<User>> = flow {
//auth -> authDto -> InterActions -> userDto -> user
try {
emit(DataState.loading())
delay(1000)
if (isNetworkAvailable) {
val networkUser = postLoginFromNetwork(auth)
if (networkUser != null) {
emit(DataState.success(networkUser))
}else {
emit(DataState.error<User>("User data is null"))
}
}else {
emit(DataState.error<User>("Unable to connect network"))
}
}catch (e: Exception) {
emit(DataState.error<User>(e.message?: "Unknown Error"))
}
}
private suspend fun postLoginFromNetwork(auth: Auth): User {
return userDtoMapper.mapToDomainModel(apiService.login(authDtoMapper.fromDomain(auth)))
}
}
主屏幕
@Composable
fun HomeScreen() {
Card(
modifier = Modifier.fillMaxSize()
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "HomeScreen",
fontWeight = FontWeight.Bold,
fontSize = 40.sp
)
}
}
}
您好,我通过在 LoginScreen
上按 Login
按钮成功登录后将上面的代码转到 HomeScreen
。
确认沟通顺畅,也带来了价值
但是,当我尝试调试时,我确认这部分在登录屏幕上重复完成。
user?.let {
val route = Screen.Home.route
onNavigateToHomeScreen(route)
}
如您所见,当用户有一个值时,屏幕会移动,但那部分是重复完成的,所以 HomeScreen
屏幕像闪光一样闪烁。
这就是我问你这个问题的原因。沟通后数值改变时,请告诉我如何移动屏幕。
使用 LauchedEffect
LaunchedEffect(user){
user.let {
navController.navigate("")
}
}