使用 SharedPreferences 将各个生命周期点的字符串保存和恢复到 EditText 的正确方法?

Correct way to save and restore a string at various Lifecycle points to an EditText using SharedPreferences?

我在任何地方都找不到很好的明确答案(也许我不擅长搜索?)

androidActivity Lifecycle 有各种事件会导致用户丢失 EditText 内容,除非您在生命周期事件期间保存和恢复它 - 通常使用共享首选项。听起来很简单,但我无法在实践中发挥作用;尽管在每个事件中都记录了 EditText 内容,但当我导航到另一个应用程序然后再次返回时,它并没有在我的设备上更新。

我让用户在 EditText 字段中键入序列号。这是我在 activity:

中所做的
private lateinit var sharedPref: SharedPreferences

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // (boilerplate databinding code omitted here)
    sharedPref = getPreferences(Context.MODE_PRIVATE)
}

private fun loadSN() {
    if(sharedPref.contains(PREFERENCE_SN)) {
        binding.serialNumberEditText.setText(sharedPref.getString(PREFERENCE_SN, ""))
        Log.d(TAG, "serialNumberEditText is now ${binding.serialNumberEditText.text.toString()}")
    }
}

private fun saveSN() {
    Log.d(TAG, "saveSN: saving ${binding.serialNumberEditText.text.toString()}")
    with (sharedPref.edit()) {
        putString(PREFERENCE_SN, binding.serialNumberEditText.text.toString())
        apply()
    }
}

override fun onStart() {
    super.onStart()
    loadSN()
}
override fun onPause() {
    super.onPause()
    saveSN()
}

override fun onStop() {
    super.onStop()
    saveSN()
}
override fun onResume() {
    super.onResume()
    loadSN()
}
override fun onRestart() {
    super.onRestart()
    loadSN()
}

导航到其他应用然后再次返回时的示例日志输出:

[navigate away from app]
D/FooActivity: saveSN: saving ABCDE
[^^ return to app here]
D/FooActivity: serialNumberEditText is now ABCDE
D/FooActivity: savePreference was called, restoring ABCDE
D/FooActivity: serialNumberEditText is now ABCDE
D/FooActivity: savePreference was called, restoring ABCDE
D/FooActivity: serialNumberEditText is now ABCDE
D/FooActivity: savePreference was called, restoring ABCDE

但它没有将 ABCDE 恢复到 EditText 字段。为什么?

您可以使用 viewModel 和保存状态模块来为您完成这项工作。 将此添加到 gradle(应用级别):

 dependencies {
        // Java language implementation
        implementation "androidx.savedstate:savedstate:1.0.0"
    
        // Kotlin
        implementation "androidx.savedstate:savedstate-ktx:1.1.0-rc01"
    }

如果您不想使用模块,您可以通过以下方式保存状态:

     @Override
        protected void onSaveInstanceState(@NonNull Bundle outState) {
            outState.putString("edit_text", yourEditTextView.getText().toString());
 super.onSaveInstanceState(outState);
        }

并检索此值

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState!=null){
            if (savedInstanceState.containsKey("edit_text")){
                String valueForEditText = savedInstanceState.getString("edit_text");
                yourEditTextView.setText(valueForEditText);
            }
        }

您不应该在停止和暂停时保存状态,只需在创建时定义您的编辑文本,android 会为您完成。

框架会自动为您保存当前布局中Views(包括EditTexts)的状态,但仅限于应用程序处于“后台”时。这包括当应用程序被系统销毁以回收内存时,视图将按原样恢复 - 但如果用户将应用程序滑开以明确关闭它,或者如果您通过例如删除布局,则不会。移动到另一个 Activity。如果您希望下次用户打开该布局时显示相同的数据,您需要自己保持状态,这确实意味着使用 SharedPreferences.

从您的日志来看,恢复似乎进展顺利?你存的是ABCDE,你下次回来的时候设置成ABCDE,然后你查看EditText的内容,设置成ABCDE?您看到的是什么,是否还有其他任何东西可以在该视图上设置数据,例如 XML 中的数据绑定?系统会在 onStart 之前恢复视图状态,因此您的恢复会在那之后发生,但如果有任何保存的状态,它应该与您保存的数据相同。