Kotlin使用SharedPreferences 应用关闭后TextView值未保存且崩溃
问题排查结果
直接崩溃原因
你的崩溃是TextView.setText()参数类型用错导致的:
- 你从SharedPreferences取到的
intNumber是Int类型,直接调用tvAdsAmount.setText(intNumber)时,Android系统会把传入的Int值当作res/values/strings.xml里的字符串资源ID去查找对应资源,当你存的计数是1时,系统就会查找ID为0x1的字符串,找不到就抛出Resources$NotFoundException直接崩溃。 - 给TextView设置非资源类的文本时,必须传入String类型,不能直接传Int值。
数据无法持久化原因
你选的保存时机完全错误:
finishAffinity()不是Activity的标准生命周期回调,只有你主动调用这个方法关闭任务栈里所有Activity时才会走,用户按Home键退后台、直接划掉杀进程、系统回收内存杀应用时都不会触发这个方法,保存逻辑根本不会执行,自然存不住数据。- 另外你代码里存在控件名拼写不一致的问题:
onResume里传的是tvAdAmounts,实际操作的控件是tvAdsAmount,很容易引发空指针或者操作错对象的问题。
修正后的可运行实现
- 按钮点击自增逻辑,数值变更后立刻写入,避免漏存:
// 按钮点击监听内的计数逻辑 // 用toIntOrNull做容错,避免文本为空时转换崩溃 var currentCount = tvAdsAmount.text.toString().toIntOrNull() ?: 0 currentCount++ tvAdsAmount.text = currentCount.toString() // 数值变了立刻存,不用等应用关闭 saveCount(currentCount)
- SharedPreferences读写逻辑,去掉冗余的View参数,避免传错对象:
override fun onResume() { super.onResume() // 页面回到前台时读取之前存的计数,回填到TextView val savedCount = getSavedCount() tvAdsAmount.text = savedCount.toString() } // 读取存好的计数 private fun getSavedCount(): Int { val sharedPref = getPreferences(Context.MODE_PRIVATE) // 首次安装没存过数据时默认返回0即可 return sharedPref.getInt("click_count", 0) } // 保存计数到SharedPreferences private fun saveCount(count: Int) { val sharedPref = getPreferences(Context.MODE_PRIVATE) sharedPref.edit() .putInt("click_count", count) .apply() // 用apply异步写入即可,不会卡主线程,不需要用commit同步提交 }
开发注意点
- 给TextView设置自定义文本时,只要传入的是数字、拼接字符串这类非资源内容,必须转成String类型再调用
setText(),不要直接传Int值,否则一定会触发资源查找的崩溃。 - 不要依赖
finishAffinity()、onDestroy()这类触发时机不确定的方法做数据持久化,最优方案是数据发生变更时立刻写入,退而求其次可以放在onPause()回调里写入——这个回调是Activity退到后台、被销毁前必然会触发的,能最大程度避免数据丢失。 - 做字符串转数字操作时优先用
toIntOrNull()做容错,避免TextView内容为空、被篡改成非数字内容时抛出类型转换崩溃。
内容的提问来源于stack exchange,提问作者Camp Nerd
相关产品推荐
相关产品推荐

