使用 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 会为您完成。
框架会自动为您保存当前布局中View
s(包括EditText
s)的状态,但仅限于应用程序处于“后台”时。这包括当应用程序被系统销毁以回收内存时,视图将按原样恢复 - 但如果用户将应用程序滑开以明确关闭它,或者如果您通过例如删除布局,则不会。移动到另一个 Activity
。如果您希望下次用户打开该布局时显示相同的数据,您需要自己保持状态,这确实意味着使用 SharedPreferences
.
从您的日志来看,恢复似乎进展顺利?你存的是ABCDE
,你下次回来的时候设置成ABCDE
,然后你查看EditText
的内容,设置成ABCDE
?您看到的是什么,是否还有其他任何东西可以在该视图上设置数据,例如 XML 中的数据绑定?系统会在 onStart
之前恢复视图状态,因此您的恢复会在那之后发生,但如果有任何保存的状态,它应该与您保存的数据相同。
我在任何地方都找不到很好的明确答案(也许我不擅长搜索?)
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 会为您完成。
框架会自动为您保存当前布局中View
s(包括EditText
s)的状态,但仅限于应用程序处于“后台”时。这包括当应用程序被系统销毁以回收内存时,视图将按原样恢复 - 但如果用户将应用程序滑开以明确关闭它,或者如果您通过例如删除布局,则不会。移动到另一个 Activity
。如果您希望下次用户打开该布局时显示相同的数据,您需要自己保持状态,这确实意味着使用 SharedPreferences
.
从您的日志来看,恢复似乎进展顺利?你存的是ABCDE
,你下次回来的时候设置成ABCDE
,然后你查看EditText
的内容,设置成ABCDE
?您看到的是什么,是否还有其他任何东西可以在该视图上设置数据,例如 XML 中的数据绑定?系统会在 onStart
之前恢复视图状态,因此您的恢复会在那之后发生,但如果有任何保存的状态,它应该与您保存的数据相同。