Белый экран и приложение зависают при двойном нажатии верхней кнопки навигации в приложении Android Jetpack Compose.Android

Форум для тех, кто программирует под Android
Anonymous
Белый экран и приложение зависают при двойном нажатии верхней кнопки навигации в приложении Android Jetpack Compose.

Сообщение Anonymous »

В моем приложении я использую TopAppBar со значком гамбургера и NavigationView (ModalNavigationDrawer + ModalDrawerSheet). Проблема заключается в том, что я дважды нажимаю значок навигации или когда я нажимаю значок навигации на экране настроек, а затем снова нажимаю на значок навигации дома. Странное поведение происходит, когда приложение показывает белый экран, например зависает, и у меня не было ошибок или исключений.
Вот GIF-файл, показывающий проблему
Изображение

Мой код:
MainAppNavGraph
@Composable
fun MainAppNavGraph(
currentUser: FirebaseUser?, onLogout: () -> Unit,
networkStatus: NetworkStatus,
snackbarHostState: SnackbarHostState
) {
val navController = rememberNavController()
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
val context = LocalContext.current

val currentBackStack by navController.currentBackStackEntryAsState()
val currentRoute = currentBackStack?.destination?.route

val drawerItems = listOf(
DrawerItem("home", "Home", Icons.Default.Home, route = Routes.HomeScreen.route),
DrawerItem("profile", "Profile", Icons.Default.Person, route = Routes.ProfileScreen.route),
DrawerItem(
"leader_board",
"Leader Board",
Icons.Default.Leaderboard,
route = Routes.LeaderboardScreen.route
),

DrawerItem(
"remove_ads_for_30_mins",
"Remove Ads?",
iconRes = R.drawable.ad_blocker,
route = null
),

DrawerItem(
id = "settings",
title = "Settings",
iconImageVector = Icons.Default.Settings,
route = Routes.SettingsScreen.route
)
)

val authViewModel = hiltViewModel()
val userState by authViewModel.userData.collectAsState()
val quizViewModel = hiltViewModel()

var drawerGesturesEnabled by remember { mutableStateOf(true) }

LaunchedEffect(currentUser?.uid) {
currentUser?.uid?.let {
authViewModel.loadUserData(it)
}
}

LaunchedEffect(currentRoute) {
drawerGesturesEnabled =
(currentRoute != Routes.PrivacyPolicyScreen.route && currentRoute != Routes.TermsAndConditionsScreen.route)

if (currentRoute == Routes.PrivacyPolicyScreen.route
|| currentRoute == Routes.TermsAndConditionsScreen.route
) {
scope.launch { drawerState.close() }
}
}

val userName = (userState as? Resource.Success)?.data?.userName ?: "No User Logged"

val userEmail =
(userState as? Resource.Success)?.data?.email ?: "No Email"

ModalNavigationDrawer(
drawerState = drawerState,
gesturesEnabled = drawerGesturesEnabled,
drawerContent = {
ModalDrawerSheet(
windowInsets = WindowInsets(0, 0, 0, 0),
drawerContainerColor = MaterialTheme.colorScheme.surface,
) {
AppDrawer(
currentRoute = currentRoute ?: Routes.HomeScreen.route,
userName = userName, // ← من ViewModel لاحقاً
userEmail = userEmail,
drawerItems = drawerItems,
onItemClick = { item ->
item.route?.let {
navController.navigate(it) {
popUpTo(Routes.HomeScreen.route) { saveState = true }
launchSingleTop = true
restoreState = true
}
}
},
onLogoutClick = {
scope.launch { drawerState.close() }
authViewModel.logout()
onLogout()
},
onCloseDrawer = {
scope.launch { drawerState.close() }
},
onRemoveAdsClick = {
if (AdManager.areAdsDisabled()) {
Toast.makeText(
context,
"Ads disabled — ${AdManager.getRemainingMinutes()} minutes remaining",
Toast.LENGTH_SHORT
).show()
} else if (AdManager.isRewardedReady()) {
AdManager.showRewardedAd(
activity = context as Activity,
onSessionActivated = { remaining ->
Toast.makeText(
context,
"🎉 Ads disabled for $remaining minutes!",
Toast.LENGTH_LONG
).show()

},
onNotReady = {
Toast.makeText(
context,
"Ad not ready, try again",
Toast.LENGTH_SHORT
).show()
AdManager.loadRewardedAd(context)
}
)
} else {
Toast.makeText(context, "Loading ad, try again", Toast.LENGTH_SHORT)
.show()
AdManager.loadRewardedAd(context)
}
}
)
}
}
) {
NavHost(
navController = navController,
startDestination = Routes.HomeScreen.route
) {
composable(route = Routes.HomeScreen.route) {
val homeScreenViewModel = hiltViewModel()
val state by homeScreenViewModel.homeState.collectAsState()
var isDrawerOpening by remember { mutableStateOf(false) }

HomeScreen(
stateHomeScreen = state,
event = homeScreenViewModel::onEvent,
navController = navController,
onMenuClick = {
if (!isDrawerOpening && !drawerState.isOpen) {
isDrawerOpening = true
scope.launch {
drawerState.open()
isDrawerOpening = false
}
}
},
networkStatus = networkStatus,
snackbarHostState = snackbarHostState
)
}

composable(
route = Routes.QuizScreen.route, arguments = listOf(
navArgument(ARG_KEY_QUIZ_NUMBER) { type = NavType.IntType },
navArgument(ARG_KEY_QUIZ_CATEGORY) { type = NavType.StringType },
navArgument(ARG_KEY_QUIZ_DIFFICULTY) { type = NavType.StringType },
navArgument(ARG_KEY_QUIZ_TYPE) { type = NavType.StringType },
)
) {

val state by quizViewModel.quizList.collectAsState()
QuizScreen(
numberOfQuizzes = it.arguments?.getInt(ARG_KEY_QUIZ_NUMBER)!!,
quizCategory = it.arguments?.getString(ARG_KEY_QUIZ_CATEGORY)!!,
quizDifficulty = it.arguments?.getString(ARG_KEY_QUIZ_DIFFICULTY)!!,
quizType = it.arguments?.getString(ARG_KEY_QUIZ_TYPE)!!,
event = quizViewModel::onEvent,
state = state,
navController = navController
)
}

composable(
route = Routes.ScoreScreen.route,
arguments = listOf(
navArgument(NOQ_KEY) { type = NavType.IntType },
navArgument(CORRECT_ANSWERS_KEY) { type = NavType.IntType }
)
) {
ScoreScreen(
numberOfQuestions = it.arguments?.getInt(NOQ_KEY)!!,
numberOfCorrectAnswers = it.arguments?.getInt(CORRECT_ANSWERS_KEY)!!,
onClose = {
navController.navigate(Routes.HomeScreen.route) {
popUpTo(Routes.HomeScreen.route) { inclusive = true }
}
},
quizStates = quizViewModel.quizList.collectAsState().value.quizState,
onReviewAnswers = { navController.navigate(Routes.ReviewAnswersScreen.route) }

)
}

composable(route = Routes.LeaderboardScreen.route) {
LeaderboardScreen()
}

composable(route = Routes.SettingsScreen.route) {
SettingsScreen(
onBackClick = { navController.popBackStack() },
onPrivacyPolicyClick = { navController.navigate(Routes.PrivacyPolicyScreen.route) },
onTermsClick = { navController.navigate(Routes.TermsAndConditionsScreen.route) }
)
}

composable(route = Routes.ProfileScreen.route) {

ProfileScreen(
userName = userName,
userEmail = userEmail,
onLogoutClick = {
scope.launch { drawerState.close() }
authViewModel.logout()
onLogout()
}

)
}

composable(route = Routes.ReviewAnswersScreen.route) {
val state by quizViewModel.quizList.collectAsState() // instance
ReviewAnswersScreen(
quizStates = state.quizState,
onBack = { navController.popBackStack() }
)
}

composable(route = Routes.PrivacyPolicyScreen.route) {
PrivacyPolicyScreen {
navController.popBackStack()
}
}

composable(route = Routes.TermsAndConditionsScreen.route) {
TermsAndConditionsScreen {
navController.popBackStack()
}
}

}

}
}

HomeHeader
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeHeader(
onMenuClicked: () -> Unit = {},
onSettingsClicked: () -> Unit = {}
) {
TopAppBar(
title = {
Text( modifier = Modifier.fillMaxWidth(),
text = "Quizzy",
fontSize = HeroTextSize,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.secondary,

textAlign = TextAlign.Center
)
},
navigationIcon = {
IconButton(
onClick = onMenuClicked,
modifier = Modifier
.size(40.dp)
.padding(start = 8.dp),
) {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
tint = MaterialTheme.colorScheme.secondary,
)
}
},
actions = {

IconButton(onClick = onSettingsClicked) {
Icon(
contentDescription = "Settings",
tint = colorResource(R.color.colorSecondary),
imageVector = Icons.Default.Settings,

)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = colorResource(R.color.colorPrimaryVariant)
),

modifier = Modifier.clip(
RoundedCornerShape(
bottomStart = Dimens.LargeCornerRadius,
bottomEnd = Dimens.LargeCornerRadius
)
)
)
}

Вернуться в «Android»