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

Jetpack Compose卡片状态不同步及返回页面不重组问题求助

问题描述

bug演示

所有爱心图标状态本应保持同步,但返回选餐页面时,卡片并未发生重组(尽管日志显示已执行重组操作)。若返回主页面后重新进入选餐页面,则卡片可正常重组。

尝试将状态移至卡片组件外部,但无法在卡片内部修改该状态。

相关代码

ViewModel

data class SelectMealUiState(
   val meals: List<Meal> = listOf()
)
 
class SelectMealViewModel(
    mealsRepository: IMealsRepository,
    firebaseAuth: FirebaseAuth
) : MealViewModel(mealsRepository, firebaseAuth = firebaseAuth) {
 
    private var _selectMealUiState: MutableStateFlow<SelectMealUiState> = MutableStateFlow(SelectMealUiState())
    val selectMealUiState: StateFlow<SelectMealUiState> get() = _selectMealUiState.asStateFlow()
 
    fun updateState(category: String) {
        viewModelScope.coroutineContext.cancelChildren()
        viewModelScope.launch(dispatcherIo) {
                    mealsRepository.getAllLocalMealsByCategoryFlow(category).collect {
                        _selectMealUiState.update { currentState ->
                            currentState.copy(meals = it)
                }
            }
        }
    }
}

Screen

const val TAG = "SelectMealScreen"
 
@Composable
fun SelectMealScreen(
    categoryName: String,
    viewModelSelectMeal: SelectMealViewModel = viewModel(factory = AppViewModelProvider.Factory),
    viewModelAuth: AuthViewModel = viewModel(factory = AppViewModelProvider.Factory),
    navController: NavController,
    refreshCallback : () -> Unit,
    favoriteCallback: () -> Unit,
    loginRegisterCallback: () -> Unit,
    isBackEnabled: Boolean,
    navBack: () -> Unit,
    modifier :  Modifier = Modifier
) {
    val selectMealUiState by viewModelSelectMeal.selectMealUiState.collectAsState()
 
    val firebaseAuth: FirebaseAuth by lazy {
        FirebaseAuth.getInstance()
    }
 
    val isUserLoggedIn by remember {
        mutableStateOf(firebaseAuth.currentUser != null)
    }
 
    LaunchedEffect(true) {
        Log.d(TAG, "update state meals selection screen")
        viewModelSelectMeal.updateState(categoryName)
    }
 
    Log.d(TAG, "Recomposition! isUserLoggedIn: $isUserLoggedIn")
 
    Scaffold(
        topBar = {
            TopBar(
                favoriteCallback = favoriteCallback,
                refreshCallback = refreshCallback,
                userCallback = loginRegisterCallback,
                isBackEnabled = isBackEnabled,
                backCallBack = navBack
        ) },
        modifier = Modifier.fillMaxSize()
    ) {
            innerPadding ->
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = modifier
                .fillMaxSize()
                .padding(innerPadding)
        ) {
            Text(text = categoryName, fontSize = 30.sp, modifier = Modifier.padding(vertical = 10.dp))
            MealsGrid(
                mealsList = selectMealUiState.meals,
                navController = navController,
                isUserLoggedIn = isUserLoggedIn,
                viewModelSelectMeal = viewModelSelectMeal
            )
        }
 
    }
 
}
 
@Composable
fun MealsGrid(
    mealsList: List<Meal>,
    navController: NavController,
    viewModelSelectMeal: SelectMealViewModel,
    isUserLoggedIn: Boolean
) {
 
    LazyVerticalGrid(
        columns = GridCells.Fixed(2),
        contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // TODO gestisci caso in cui non ci sono elementi in memoria
        items(mealsList, key = { meal -> meal.idMeal }) {
                meal ->
            MealsCard(
                meal = meal,
                setfavoriteCallBack = { if (isUserLoggedIn) {
                                                viewModelSelectMeal.uploadOnRemoteAndSetLocally(mealId = meal.idMeal)
                                            }
                                        else {
                                                viewModelSelectMeal.setLocalMealAsFavorite(meal.idMeal);
                                        }
                                        Log.d(TAG, "Card set heart icon callback ${this.hashCode()}")
                                      },
                unsetfavoriteCallBack = {
                                        if (isUserLoggedIn) {
                                            viewModelSelectMeal.removeFromRemoteAndUnsetLocally(mealId = meal.idMeal)
                                        }
                                        else {
                                            viewModelSelectMeal.unsetLocalMealAsFavorite(meal.idMeal)
                                            }
                                        Log.d(TAG, "Card unset heart icon callback $this.hashcode")
                },
                onClickCallback = { navController.navigate("Detail" + "/" + meal.idMeal) }
            )
        }
    }
}
 
@Composable
fun MealsCard(
    meal: Meal,
    setfavoriteCallBack: () -> Unit,
    unsetfavoriteCallBack: () -> Unit,
    onClickCallback: () -> Unit
) {
    ElevatedCard(
        elevation = CardDefaults.cardElevation(
            defaultElevation = 6.dp
        ),
        onClick = onClickCallback,
        shape = MaterialTheme.shapes.medium,
        modifier = Modifier.height(210.dp)
    ) {
        var isMealFlaggedAsFavorite by rememberSaveable {
            mutableStateOf(meal.isFavorite)
        }
 
        Log.d(TAG,
            "recomposition, favorite state of the card ${meal.idMeal} $isMealFlaggedAsFavorite"
        )
 
        Column {
            Row(
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.Center,
                modifier = Modifier.fillMaxWidth()
            ) {
                Box(modifier = Modifier.width(120.dp)){
                    Text(meal.strMeal)
                }
                Box(modifier = Modifier.width(20.dp)) {
 
                    val unsetAndChangeHeart: () -> Unit = {
                        unsetfavoriteCallBack()
                        isMealFlaggedAsFavorite = "0"
                    }
 
                    val setAndChangeHeart: () -> Unit = {
                        setfavoriteCallBack()
                        isMealFlaggedAsFavorite = "1"
                    }
 
                    if(isMealFlaggedAsFavorite == "1") {
                        IconButton(onClick = unsetAndChangeHeart ) {
                            Icon(
                                imageVector = Icons.Filled.Favorite,
                                contentDescription = ""
                            )
                        }
                    }
                    else {
                        IconButton(onClick = setAndChangeHeart) {
                            Icon(
                                imageVector = Icons.Outlined.FavoriteBorder,
                                contentDescription = ""
                            )
                        }
                    }
                }
            }
            Box{
                AsyncImage(
                    model = meal.strMealThumb,
                    contentDescription = "",
                    error = painterResource(R.drawable.ic_broken_image),
                    placeholder = painterResource(R.drawable.loading_img),
                    contentScale = ContentScale.Crop
                )
            }
        }
 
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:05:54