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

如何在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()
        }
    }
}

方案说明

  1. SharedPreferences持久化:

    • 每次EditText内容变化时,自动将值保存到SharedPreferences,即使应用完全关闭并重启,下次打开Fragment时会自动读取并填充。
    • 使用apply()方法异步保存,避免阻塞UI线程。
  2. Fragment实例复用:

    • 通过标签查找已存在的Fragment实例,避免每次切换都创建新对象,减少资源消耗的同时,也能保留Fragment的内存状态(结合SharedPreferences双重保障)。

额外优化建议

  • 如果需要清除保存的值,可以添加一个清除按钮,调用sharedPrefs.edit().clear().apply()。
  • 对于数字输入的EditText,可以在布局中设置android:inputType="numberDecimal",限制输入格式,减少NumberFormatException的概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:10:35