如何在Kotlin中保存EditText值,切换Fragment不丢失直至应用销毁
解决方案:持久化EditText输入值(Fragment切换+应用重启后恢复)
要解决Fragment切换后输入值消失,以及应用完全关闭后仍能恢复的问题,我们可以结合SharedPreferences持久化存储和Fragment实例复用两种方案,以下是详细代码修改:
步骤1:修改EstimatorFragment,实现输入值的自动保存与恢复
通过TextWatcher监听EditText内容变化,实时保存到SharedPreferences;在Fragment创建时读取存储的值并填充到EditText:
class EstimatorFragment : Fragment() { lateinit var etPerson: EditText lateinit var etPetrol: EditText lateinit var etElectricity: EditText lateinit var etWater: EditText lateinit var etLpg: EditText lateinit var etHouseTravel: EditText lateinit var etSchool: EditText lateinit var etVacation: EditText lateinit var btnGetResults: Button // 定义SharedPreferences实例,用于持久化存储 private lateinit var sharedPrefs: SharedPreferences override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_estimator, container, false) // 初始化SharedPreferences,使用Activity的Context避免内存泄漏 sharedPrefs = requireActivity().getSharedPreferences("EstimatorPrefs", Context.MODE_PRIVATE) // 初始化控件 etPerson = view.findViewById(R.id.etPerson) etPetrol = view.findViewById(R.id.etPetrol) etElectricity = view.findViewById(R.id.etElectricity) etWater = view.findViewById(R.id.etWater) etLpg = view.findViewById(R.id.etLpg) etHouseTravel = view.findViewById(R.id.etHouseTravel) etSchool = view.findViewById(R.id.etSchool) etVacation = view.findViewById(R.id.etVacation) btnGetResults = view.findViewById(R.id.btnGetResults) // 恢复之前保存的输入值 restoreInputValues() // 给每个EditText添加内容变化监听,实时保存 setupTextWatchers() btnGetResults.setOnClickListener { // 保留原有计算和跳转逻辑 val registerUser = JSONObject() registerUser.put("name", etPerson.text) try { var person = etPerson.text.toString().toDouble() val mul1 = (person * 364).toFloat() val a = mul1.toString() var petrol = etPetrol.text.toString().toDouble() val mul2 = (petrol * (0.022772278*12)).toFloat() val b = mul2.toString() var electricity = etElectricity.text.toString().toDouble() val mul3 = (electricity * 12*(0.92/7)).toFloat() val c = mul3.toString() var water = etWater.text.toString().toDouble() val mul4 = (water * 179.4/325).toFloat() val d = mul4.toString() var lpg = etLpg.text.toString().toDouble() val mul5 = (lpg * 280.705152/0.6).toFloat() val e = mul5.toString() var travel = etHouseTravel.text.toString().toDouble() val mul6 = (travel * 83.72/1.5).toFloat() val f = mul6.toString() var school = etSchool.text.toString().toDouble() val mul7 = (school * 502.32/9).toFloat() val g = mul7.toString() var vacation = etVacation.text.toString().toDouble() val mul8 = (vacation * 383.333333/2000).toFloat() val h = mul8.toString() val fin = mul1 + mul2 + mul3 + mul4 + mul5 + mul6 + mul7 + mul8 val final = fin.toString() val intent = Intent(activity, Results::class.java) intent.putExtra("A", a) intent.putExtra("B", b) intent.putExtra("C", c) intent.putExtra("D", d) intent.putExtra("E", e) intent.putExtra("F", f) intent.putExtra("G", g) intent.putExtra("H", h) intent.putExtra("FIN", final) startActivity(intent) } catch(e:NumberFormatException ) { val alterDialog = AlertDialog.Builder(activity as Context) alterDialog.setTitle("Enter All The Values!") alterDialog.setMessage("Enter 0 if any block is blank!") alterDialog.setPositiveButton("Ok") { _, _ -> } alterDialog.create() alterDialog.show() } } return view } // 从SharedPreferences恢复输入值 private fun restoreInputValues() { etPerson.setText(sharedPrefs.getString("key_person", "")) etPetrol.setText(sharedPrefs.getString("key_petrol", "")) etElectricity.setText(sharedPrefs.getString("key_electricity", "")) etWater.setText(sharedPrefs.getString("key_water", "")) etLpg.setText(sharedPrefs.getString("key_lpg", "")) etHouseTravel.setText(sharedPrefs.getString("key_travel", "")) etSchool.setText(sharedPrefs.getString("key_school", "")) etVacation.setText(sharedPrefs.getString("key_vacation", "")) } // 设置EditText内容变化监听,实时保存到SharedPreferences private fun setupTextWatchers() { etPerson.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_person", s.toString()).apply() } }) etPetrol.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_petrol", s.toString()).apply() } }) etElectricity.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_electricity", s.toString()).apply() } }) etWater.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_water", s.toString()).apply() } }) etLpg.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_lpg", s.toString()).apply() } }) etHouseTravel.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_travel", s.toString()).apply() } }) etSchool.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_school", s.toString()).apply() } }) etVacation.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { sharedPrefs.edit().putString("key_vacation", s.toString()).apply() } }) } }
步骤2:修改MainActivity,复用EstimatorFragment实例
当前每次调用openEstimator()都会创建新的Fragment实例,导致之前的输入状态丢失。修改该方法,优先复用已存在的Fragment:
class MainActivity : AppCompatActivity() { lateinit var drawerLayout: DrawerLayout lateinit var coordinatorLayout: CoordinatorLayout lateinit var toolbar: Toolbar lateinit var frameLayout: FrameLayout lateinit var navigationView: NavigationView var previousMenuItem: MenuItem? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) drawerLayout = findViewById(R.id.drawerLayout) coordinatorLayout = findViewById(R.id.coordinatorLayout) toolbar = findViewById(R.id.toolbar) frameLayout = findViewById(R.id.frame) navigationView = findViewById(R.id.navigationView) setUpToolbar() openEstimator() val actionBarDrawerToggle = ActionBarDrawerToggle( this@MainActivity, drawerLayout, R.string.open_drawer, R.string.close_drawer ) drawerLayout.addDrawerListener(actionBarDrawerToggle) actionBarDrawerToggle.syncState() navigationView.setNavigationItemSelectedListener { if (previousMenuItem != null){ previousMenuItem?.isChecked = false } it.isCheckable = true it.isChecked = true previousMenuItem = it when(it.itemId){ R.id.estimator -> { openEstimator() drawerLayout.closeDrawers() } R.id.aboutApp -> { supportFragmentManager.beginTransaction() .replace( R.id.frame, AboutAppFragment() ) .commit() supportActionBar?.title = "About App" drawerLayout.closeDrawers() } } return@setNavigationItemSelectedListener true } } override fun onOptionsItemSelected(item: MenuItem): Boolean { val id = item.itemId if (id == android.R.id.home){ drawerLayout.openDrawer(GravityCompat.START) } return super.onOptionsItemSelected(item) } // 修改openEstimator方法,复用Fragment实例 fun openEstimator(){ // 先查找是否已存在EstimatorFragment实例 var fragment = supportFragmentManager.findFragmentByTag("EstimatorFragment") as EstimatorFragment? if (fragment == null) { fragment = EstimatorFragment() } val transaction = supportFragmentManager.beginTransaction() transaction.replace(R.id.frame, fragment, "EstimatorFragment") transaction.commit() supportActionBar?.title = "Estimator" navigationView.setCheckedItem(R.id.estimator) } fun setUpToolbar() { setSupportActionBar(toolbar) supportActionBar?.title = "Toolbar Title" supportActionBar?.setHomeButtonEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true) } override fun onBackPressed() { val frag = supportFragmentManager.findFragmentById(R.id.frame) when(frag){ !is EstimatorFragment -> openEstimator() else -> super.onBackPressed() } } }
方案说明
SharedPreferences持久化:
- 每次EditText内容变化时,自动将值保存到SharedPreferences,即使应用完全关闭并重启,下次打开Fragment时会自动读取并填充。
- 使用
apply()方法异步保存,避免阻塞UI线程。
Fragment实例复用:
- 通过标签查找已存在的Fragment实例,避免每次切换都创建新对象,减少资源消耗的同时,也能保留Fragment的内存状态(结合SharedPreferences双重保障)。
额外优化建议
- 如果需要清除保存的值,可以添加一个清除按钮,调用
sharedPrefs.edit().clear().apply()。 - 对于数字输入的EditText,可以在布局中设置
android:inputType="numberDecimal",限制输入格式,减少NumberFormatException的概率。
内容的提问来源于stack exchange,提问作者Rushi Mayur
相关产品推荐
相关产品推荐

