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

如何在Jetpack Compose中重启App后保存开关按钮状态(Firebase实现)

解决Firebase Firestore保存收藏按钮状态问题

问题分析

你的代码目前存在几个关键问题导致重启后状态丢失:

  • 初始化时没有从Firestore读取已保存的收藏状态,isFavorite默认始终为false
  • 收藏状态切换时仅修改了本地状态,取消收藏的操作未同步到Firestore
  • 存储到Firestore时,使用的是原始shoe对象的isFavorite,而非ViewModel中更新后的状态
  • 没有监听Firestore文档变化,无法实时同步状态到UI

修复方案

1. 修改ViewModel:实现状态读取与双向同步

更新FirebaseFirestoreVM,完成从Firestore加载初始状态、切换状态时同步云端(含取消收藏逻辑):

class FirebaseFirestoreVM(private val shoeId: String) : ViewModel() {
    val isFavorite: MutableState<Boolean> = mutableStateOf(false)
    private val db = FirebaseFirestore.getInstance()
    private lateinit var snapshotListener: ListenerRegistration

    init {
        // 从Firestore加载初始收藏状态
        loadFavoriteState()
    }

    private fun loadFavoriteState() {
        snapshotListener = db.collection("shoes").document(shoeId)
            .addSnapshotListener { snapshot, error ->
                if (error != null) {
                    // 可添加错误日志处理
                    return@addSnapshotListener
                }
                snapshot?.let { doc ->
                    val shoe = doc.toObject(ShoeModel::class.java)
                    isFavorite.value = shoe?.isFavorite ?: false
                }
            }
    }

    // 切换收藏状态并同步到Firestore
    fun toggleFavorite(shoe: ShoeModel) {
        val newState = !isFavorite.value
        isFavorite.value = newState
        // 更新Firestore中的isFavorite字段
        db.collection("shoes").document(shoeId)
            .update("isFavorite", newState)
            .addOnFailureListener {
                // 更新失败时回滚状态
                isFavorite.value = !newState
            }
    }

    override fun onCleared() {
        super.onCleared()
        // 移除监听器防止内存泄漏
        snapshotListener.remove()
    }
}

2. 更新FavoriteButton:正确触发状态同步

修改按钮的onCheckedChange逻辑,直接调用ViewModel的toggleFavorite方法,移除冗余的条件判断:

@Composable
fun FavoriteButton(shoe: ShoeModel) {
    val myViewModel: FirebaseFirestoreVM = viewModel(
        LocalContext.current as ViewModelStoreOwner,
        key = shoe.shoeName
    )

    IconToggleButton(
        checked = myViewModel.isFavorite.value,
        onCheckedChange = {
            myViewModel.toggleFavorite(shoe)
        }
    ) {
        Icon(
            imageVector = if (myViewModel.isFavorite.value) {
                Icons.Filled.Favorite
            } else {
                Icons.Filled.FavoriteBorder
            },
            contentDescription = if (myViewModel.isFavorite.value) "取消收藏" else "添加收藏",
            tint = MaterialTheme.colors.primary
        )
    }
}

3. 确保ShoeModel数据类映射正确

确认ShoeModel包含isFavorite字段,且默认值设置合理:

data class ShoeModel(
    val shoeName: String,
    val shoeImage: String,
    val shoeDescription: String,
    val shoePrice: Double,
    val shoeFrontSide: String,
    val shoeBackSide: String,
    val shoeSide: String,
    val isFavorite: Boolean = false // 默认未收藏
)

关键说明

  • 实时同步:通过addSnapshotListener监听Firestore文档变化,确保UI与云端状态一致
  • 双向保障:点击按钮时同步更新本地与云端状态,同时处理更新失败的回滚逻辑
  • 内存防护:ViewModel销毁时移除Firestore监听器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 03:40:33