如何在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
相关产品推荐
相关产品推荐

