You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose下拉菜单无法显示已添加用户名列表的问题

Jetpack Compose下拉菜单不显示用户名问题修复

问题:注册页面输入用户名并保存后,Logcat显示ViewModel中的列表长度已更新,但首页点击菜单按钮后,下拉菜单里看不到任何用户名,调用列表时长度显示为0。

问题根源

  1. ViewModel实例不共享:注册页和首页通过viewModel()获取的ViewModel可能属于不同的ViewModelStoreOwner(比如导航栈不同),导致首页拿到的是全新的空列表实例。
  2. 状态未被Compose感知:当前ViewModel返回的是普通List,Compose无法监听列表的更新,即使列表内容变化,UI也不会自动重组刷新。

修复步骤

1. 重构ViewModel,正确暴露可观察状态

将内部的可变状态列表通过可观察的方式对外暴露,让Compose能感知变化:

data class UserNameUiState(
    val userName: String
)

class DropDownMenuViewModel: ViewModel() {
    // 内部维护的可变状态列表
    private val _userNames = mutableStateListOf<UserNameUiState>()
    
    // 对外暴露不可变的可观察列表,Compose能监听其变化
    val userNames: List<UserNameUiState> get() = _userNames

    // 添加用户名到列表
    fun addUserName(name: UserNameUiState) {
        _userNames.add(name)
    }
}

2. 确保ViewModel全局共享

在获取ViewModel时,指定使用Activity级别的ViewModelStoreOwner,保证注册页和首页使用同一个ViewModel实例:

  • 注册页修改:
@Composable
fun UserSignUpScreenInfo(
    username: String,
    navController: NavController,
    dropDownMenuViewModel: DropDownMenuViewModel = viewModel(
        viewModelStoreOwner = LocalViewModelStoreOwner.current!!
    )
) {
    // 原有输入逻辑不变,仅ViewModel获取方式修改
    val textFieldUserName = rememberSaveable { mutableStateOf(username) }
    
    Column(/* 原有布局代码 */) {
        // 原有TextField、按钮逻辑不变
        Button(
            onClick = {
                if(textFieldUserName.value.isNotEmpty()) {
                    dropDownMenuViewModel.addUserName(
                        UserNameUiState(userName = textFieldUserName.value)
                    )
                }
                navController.navigate(DestinationScreens.HomePage.route)
            }
        ) {
            Text(text = "Next")
        }
    }
}
  • 首页修改:
@Composable
fun HomePageTopAppBar(
    modifier: Modifier = Modifier,
    dropDownMenuViewModel: DropDownMenuViewModel = viewModel(
        viewModelStoreOwner = LocalViewModelStoreOwner.current!!
    )
) {
    var expandedMenu by remember { mutableStateOf(false) }
    // 直接使用ViewModel暴露的可观察列表
    val listItems = dropDownMenuViewModel.userNames

    Row(modifier = modifier.fillMaxWidth().background(Color.LightGray)) {
        IconButton(onClick = { expandedMenu = true }) {
            Icon(Icons.Filled.Menu, "Menu Button", tint = Color.DarkGray)
        }
        
        DropdownMenu(
            expanded = expandedMenu,
            onDismissRequest = { expandedMenu = false },
        ) {
            // 列表变化时自动重组UI
            listItems.forEach { user ->
                DropdownMenuItem(onClick = { /*TODO*/ }) {
                    Icon(Icons.Filled.AccountCircle, "Account", tint = Color.DarkGray)
                    Text(text = user.userName, modifier = Modifier.padding(start = 4.dp), color = Color.DarkGray)
                }
            }
        }
        
        Text(text = "App", textAlign = TextAlign.Center, color = Color.Red)
    }
    Divider(color = Color.DarkGray, modifier = Modifier.fillMaxWidth().width(1.dp))
}

3. 额外优化:保存输入状态

注册页的TextField状态改用rememberSaveable,避免屏幕旋转时丢失输入内容:

val textFieldUserName = rememberSaveable { mutableStateOf(username) }

内容的提问来源于stack exchange,提问作者TurboScript

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:42:51