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

如何在Kotlin中保存与恢复MutableListOf<Checkbox>状态?

如何保存并恢复MutableList的状态

核心问题

你无法直接保存Checkbox对象——Android的UI组件(View)无法被序列化存储,直接保存View不仅会导致序列化失败,还可能引发内存泄漏。正确思路是保存Checkbox的核心数据(比如文本内容),应用重启时再根据这些数据重新创建Checkbox并恢复布局。

解决方案步骤

1. 定义数据类存储Checkbox关键信息

创建一个轻量级数据类,用来保存需要恢复的Checkbox属性:

data class CheckboxData(val text: String)

2. 使用SharedPreferences存储序列化数据

SharedPreferences适合存储轻量的结构化数据,我们可以借助Gson将List<CheckboxData>转为JSON字符串存储(也可以用Android自带的JSON工具类)。

3. 修改Activity代码实现完整逻辑

下面是整合了保存/恢复逻辑的完整代码:

import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.CheckBox
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type

class MainActivity : AppCompatActivity() {
    private lateinit var button: Button
    private lateinit var text: TextView
    private lateinit var layout: ConstraintLayout
    private var numbers = 0
    private var checkboxes = mutableListOf<CheckBox>()
    private lateinit var prefs: android.content.SharedPreferences
    private val gson = Gson()
    private val CHECKBOX_DATA_KEY = "checkbox_data_list"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initViews()
        prefs = getSharedPreferences("CheckboxPrefs", MODE_PRIVATE)
        // 恢复之前保存的Checkbox数据
        restoreCheckboxes()

        button.setOnClickListener {
            val inputText = text.text.toString().trim()
            if (TextUtils.isEmpty(inputText)) return@setOnClickListener
            
            val checkbox = createCheckbox(inputText)
            layout.addView(checkbox)
            setupCheckboxLayoutParams(checkbox, numbers)
            numbers += 1
            checkboxes.add(checkbox)
            setupCheckboxClickListener(checkbox)
            text.text = ""
            // 添加后立即保存数据
            saveCheckboxData()
        }
    }

    private fun initViews() {
        button = findViewById(R.id.button)
        text = findViewById(R.id.editTextTextPersonName)
        layout = findViewById(R.id.layout)
    }

    private fun createCheckbox(text: String): CheckBox {
        val checkbox = CheckBox(this)
        checkbox.text = text
        checkbox.textSize = 13f
        val font = android.graphics.Typeface.create(android.graphics.Typeface.MONOSPACE, android.graphics.Typeface.BOLD)
        checkbox.typeface = font
        checkbox.id = View.generateViewId()
        return checkbox
    }

    private fun setupCheckboxLayoutParams(checkbox: CheckBox, position: Int) {
        val params = ConstraintLayout.LayoutParams(1020, 120)
        params.setMargins(100, position * 75, 100, 100)
        checkbox.layoutParams = params

        val constraintSet = ConstraintSet()
        constraintSet.clone(layout)
        constraintSet.connect(
            checkbox.id,
            ConstraintSet.TOP,
            layout.id,
            ConstraintSet.TOP,
            position * 75
        )
        constraintSet.connect(
            checkbox.id,
            ConstraintSet.START,
            layout.id,
            ConstraintSet.START,
            0
        )
        constraintSet.applyTo(layout)
    }

    private fun setupCheckboxClickListener(checkbox: CheckBox) {
        checkbox.setOnClickListener {
            checkbox.animate().alpha(1f).withEndAction {
                checkbox.isChecked = false
                layout.removeView(checkbox)
                numbers -= 1
                checkboxes.remove(checkbox)
                updateCheckboxPositions()
                // 删除后立即保存数据
                saveCheckboxData()
            }.start()
        }
    }

    private fun updateCheckboxPositions() {
        checkboxes.forEachIndexed { index, cb ->
            val params = cb.layoutParams as ConstraintLayout.LayoutParams
            params.setMargins(100, index * 75, 100, 100)
            cb.layoutParams = params

            val constraintSet = ConstraintSet()
            constraintSet.clone(layout)
            constraintSet.connect(
                cb.id,
                ConstraintSet.TOP,
                layout.id,
                ConstraintSet.TOP,
                index * 75
            )
            constraintSet.applyTo(layout)
        }
    }

    private fun saveCheckboxData() {
        // 将Checkbox列表转成可序列化的数据类列表
        val checkboxDataList = checkboxes.map { CheckboxData(it.text.toString()) }
        val json = gson.toJson(checkboxDataList)
        prefs.edit().putString(CHECKBOX_DATA_KEY, json).apply()
    }

    private fun restoreCheckboxes() {
        val json = prefs.getString(CHECKBOX_DATA_KEY, null) ?: return
        val type: Type = object : TypeToken<List<CheckboxData>>() {}.type
        val checkboxDataList: List<CheckboxData> = gson.fromJson(json, type)
        
        // 根据保存的数据重新创建Checkbox并添加到布局
        checkboxDataList.forEachIndexed { index, data ->
            val checkbox = createCheckbox(data.text)
            layout.addView(checkbox)
            setupCheckboxLayoutParams(checkbox, index)
            checkboxes.add(checkbox)
            setupCheckboxClickListener(checkbox)
        }
        numbers = checkboxDataList.size
    }

    // 应用退到后台时再次保存,避免数据丢失
    override fun onPause() {
        super.onPause()
        saveCheckboxData()
    }
}

data class CheckboxData(val text: String)

4. 添加Gson依赖(若使用)

在app模块的build.gradle(Module级别)的dependencies块中添加:

implementation 'com.google.code.gson:gson:2.10.1'

关键说明

  • 禁止保存View对象:View持有上下文引用,序列化会引发内存泄漏,且Android不支持直接序列化UI组件。
  • 实时保存数据:在添加/删除Checkbox时立即保存,同时在onPause中二次保存,确保应用切换到后台时数据不丢失。
  • 恢复时复用创建逻辑:重新构建Checkbox时,复用添加新Checkbox的布局设置逻辑,保证恢复后的UI和之前一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:05:32