Android Jetpack Compose:选项卡开关上的 ViewModel 状态重置

问题描述 投票:0回答:1

我正在开发一个 Android 应用程序,其中有一个底部栏。我正在使用 Jetpack Compose、hilt 和 ViewModel。我有一个 ViewModel (ShopListHomeViewModel) 来管理屏幕 (ShopListHomeScreen) 的状态。但是,当我切换选项卡并返回屏幕时,ViewModel 的状态会重置,导致我丢失数据并且屏幕再次加载。

你们能帮我看看遗漏和错误的地方吗?即使用户切换选项卡,我也想保留数据,因为我不想每次都加载,当我仅通过拉动刷新并创建新列表时,我会这样做。我正在添加代码和视频。谢谢

代码:

data class ShopListHomeState(
    val isLoading: Boolean = true,
    val name: String = "Test",
    val surname: String = "User"
)

@HiltViewModel
internal class ShopListHomeViewModel @Inject constructor() : ViewModel() {
    private val _state = MutableStateFlow(ShopListHomeState())
    val state: StateFlow<ShopListHomeState> = _state.asStateFlow()
    var counter: Int = 0
    init {
        viewModelScope.launch {
            delay(3000)
            _state.update { it.copy(isLoading = false) }
        }
    }

    fun handleEvent(event: ShopListHomeEvents) {
        viewModelScope.launch {
            when (event) {
                is ShopListHomeEvents.CreateNewListClicked -> {
                    _state.update { it.copy(name = counter++.toString()) }
                }
            }
        }
    }
}

和屏幕本身:

 @Composable
internal fun ShopListHomeScreen() {
    val viewModel: ShopListHomeViewModel = hiltViewModel()
    val state = viewModel.state.collectAsState()
    if (state.value.isLoading) {
        ScLoadingScreen()
    } else {
        ShopListHomeScreenContent(state.value, viewModel)
    }
}


@Composable
internal fun ShopListHomeScreenContent(
    state: ShopListHomeState,
    viewModel: ShopListHomeViewModel
) {
    Column(modifier = Modifier.padding(16.dp)) {
        ScCardItem(
            modifier = Modifier.fillMaxWidth(),
            onClick = {}
        ) {
            Box(
                modifier = Modifier
                    .padding(32.dp)
                    .fillMaxWidth(),
                contentAlignment = Alignment.TopStart,
            ) {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement
                        .spacedBy(
                            space = 16.dp,
                            alignment = Alignment.Start
                        ),
                ) {
                    Text(text = "Family List", style = ScTheme.typography.titleMedium)
                    Text(text = "Created by ${state.name}", style = ScTheme.typography.bodySmall)
                }
            }
        }
        Spacer(modifier = Modifier.weight(1f))
        ScPrimaryButton(text = "Create New List", onClick = {
            viewModel.handleEvent(ShopListHomeEvents.CreateNewListClicked)
        })
    }
}

有关导航和设置的其他代码:

@Composable
fun AppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController,
    startDestination: String = NavigationItem.Home.route,
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination,
        enterTransition = {
            EnterTransition.None
        },
        exitTransition = {
            ExitTransition.None
        }

    ) {
        composable(NavigationItem.Home.route) {
            ShopListHomeScreen()
        }
        composable(NavigationItem.Settings.route) {
            SettingsHomeScreen()
        }
        composable(NavigationItem.CreateListScreen.route) {
            ShopListCreateScreen(navController)
        }
    }
}

@Composable
internal fun SettingsHomeScreen() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(text = "Setting List", style = ScTheme.typography.titleMedium)
        Spacer(modifier = Modifier.weight(1f))
    }
}
enum class Screen {
    Home,
    Settings,
    CreateListScreen
}
sealed class NavigationItem(val route: String) {
    object Home : NavigationItem(Screen.Home.name)
    object Settings : NavigationItem(Screen.Settings.name)
    object CreateListScreen : NavigationItem(Screen.CreateListScreen.name)
}

@Composable
fun TabView(tabBarItems: List<TabBarItem>, navController: NavController) {
    var selectedTabIndex by rememberSaveable {
        mutableStateOf(0)
    }

    NavigationBar {
        tabBarItems.forEachIndexed { index, tabBarItem ->
            NavigationBarItem(
                colors = NavigationBarItemColors(
                    selectedIconColor= ScTheme.colors.neutrals.black200TextPrimary,
                    selectedTextColor = ScTheme.colors.neutrals.black200TextPrimary,
                    selectedIndicatorColor = Color.Transparent,
                    unselectedIconColor = ScTheme.colors.neutrals.grey200TitleSecondary,
                    unselectedTextColor = ScTheme.colors.neutrals.grey200TitleSecondary,
                    disabledIconColor = ScTheme.colors.neutrals.grey200TitleSecondary,
                    disabledTextColor = ScTheme.colors.neutrals.grey200TitleSecondary,
                ),
                selected = selectedTabIndex == index,
                onClick = {
                    selectedTabIndex = index
                    navController.navigate(tabBarItem.title)
                },
                icon = {
                    TabBarIconView(
                        isSelected = selectedTabIndex == index,
                        selectedIcon = tabBarItem.selectedIcon,
                        unselectedIcon = tabBarItem.unselectedIcon,
                        title = tabBarItem.title,
                    )
                },
                label = { Text(tabBarItem.title) })
        }
    }
}

@Composable
fun TabBarIconView(
    isSelected: Boolean,
    selectedIcon: ImageVector,
    unselectedIcon: ImageVector,
    title: String,
    badgeAmount: Int? = null
) {
    BadgedBox(badge = { TabBarBadgeView(badgeAmount) }) {
        Icon(
            imageVector = if (isSelected) {
                selectedIcon
            } else {
                unselectedIcon
            },
            contentDescription = title
        )
    }
}

android android-studio android-jetpack-compose android-lifecycle android-viewmodel
1个回答
0
投票

我认为您只是在

@Singleton
视图模型顶部缺少一个
ShopListHomeViewModel
标签,以确保您始终获得该类的单个实例。

或者,如果您有一个

@Provider
模块类或类似的东西来管理视图模型,您可以确保再次手动处理其中的单个实例,以便您始终从 DI 获取相同的对象。

© www.soinside.com 2019 - 2024. All rights reserved.