Android中返回父Activity时如何避免数据丢失?
嘿,这个问题我在Android开发中碰到好多次了!本质是Activity的生命周期特性搞的鬼——当你从A跳转到B时,A会进入停止状态(onStop),要是系统内存吃紧,A甚至会被销毁;就算没被销毁,默认情况下如果没做数据持久化,返回时也可能丢失之前的编辑内容和变量值。下面给你几个靠谱的解决思路:
onSaveInstanceState + onRestoreInstanceState保存临时状态 这是Android官方推荐的应对Activity临时销毁场景的方案。当Activity即将被系统销毁(比如跳转页面、屏幕旋转),系统会自动调用onSaveInstanceState,你可以在这里把需要保留的数据存入Bundle;当Activity重建时,通过onCreate或者onRestoreInstanceState把数据读回来。
举个具体的代码例子,在Activity A中实现:
// 保存数据 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 保存编辑框的文本 outState.putString("USER_EDITED_TEXT", editText.getText().toString()); // 保存自定义变量,比如一个计数变量 outState.putInt("COUNTER_VAR", mCounter); } // 在onCreate中恢复数据 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); editText = findViewById(R.id.et_input); if (savedInstanceState != null) { // 恢复文本内容 String savedText = savedInstanceState.getString("USER_EDITED_TEXT"); editText.setText(savedText); // 恢复计数变量 mCounter = savedInstanceState.getInt("COUNTER_VAR", 0); } } // 也可以用onRestoreInstanceState,它在onStart之后调用,更专注于状态恢复 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String savedText = savedInstanceState.getString("USER_EDITED_TEXT"); editText.setText(savedText); mCounter = savedInstanceState.getInt("COUNTER_VAR"); }
注意:Bundle只能存储基本数据类型、Serializable或Parcelable对象,要是你需要保存自定义类,记得让类实现这两个接口中的一个。
如果你在用Jetpack组件,那ViewModel绝对是最优解——它的生命周期独立于Activity,就算Activity被销毁重建,ViewModel依然会保留数据,完美解决返回时的数据丢失问题。
步骤很简单:
- 先创建一个ViewModel类来托管数据:
import androidx.lifecycle.ViewModel; public class ActivityAViewModel extends ViewModel { private String userEditedText = ""; private int counter = 0; // getter和setter方法 public String getUserEditedText() { return userEditedText; } public void setUserEditedText(String text) { this.userEditedText = text; } public int getCounter() { return counter; } public void setCounter(int counter) { this.counter = counter; } }
- 在Activity A中获取ViewModel实例,并同步数据:
import androidx.lifecycle.ViewModelProvider; public class ActivityA extends AppCompatActivity { private ActivityAViewModel viewModel; private EditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); // 获取ViewModel,一定要用ViewModelProvider,不能自己new! viewModel = new ViewModelProvider(this).get(ActivityAViewModel.class); editText = findViewById(R.id.et_input); // 恢复之前保存的文本 editText.setText(viewModel.getUserEditedText()); // 恢复计数变量 mCounter = viewModel.getCounter(); // 监听编辑框变化,实时保存到ViewModel editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { viewModel.setUserEditedText(s.toString()); } @Override public void afterTextChanged(Editable s) {} }); } // 当你修改计数变量时,直接同步到ViewModel private void incrementCounter() { mCounter++; viewModel.setCounter(mCounter); } }
这样不管Activity A被重建多少次,数据都稳稳存在ViewModel里,从B返回时直接就能拿到最新的内容。
如果你的数据不仅需要在返回时保留,还希望下次打开APP也能看到,那可以用SharedPreferences、Room(SQLite封装)或者文件存储。比如用SharedPreferences的话:
在Activity A中,实时保存数据:
// 获取SharedPreferences实例 SharedPreferences prefs = getSharedPreferences("MyAppData", MODE_PRIVATE); // 编辑并保存 SharedPreferences.Editor editor = prefs.edit(); editor.putString("SAVED_EDIT_TEXT", editText.getText().toString()); editor.putInt("SAVED_COUNTER", mCounter); editor.apply(); // 异步保存,不阻塞主线程 // 在onCreate中恢复数据 String savedText = prefs.getString("SAVED_EDIT_TEXT", ""); editText.setText(savedText); mCounter = prefs.getInt("SAVED_COUNTER", 0);
这种方法的好处是数据不会因为APP被杀死而丢失,但如果只是本次会话的临时数据,用前两种方法更轻量。
默认情况下,从B返回A时,A如果还在任务栈里,系统会调用onRestart和onStart,不会重建。但如果你的代码里启动B时用了FLAG_ACTIVITY_CLEAR_TOP之类的Flag,可能会导致A被销毁。这种情况下可以检查启动B的Intent代码,去掉不必要的Flag,或者把A的launchMode设为singleTop(但这只能解决栈顶的情况,无法应对系统回收的场景)。
总之,优先推荐用ViewModel(Jetpack)或者onSaveInstanceState(原生)来处理临时数据;长期数据用本地持久化;启动模式调整尽量少用,因为它解决不了系统回收Activity的核心问题。
内容的提问来源于stack exchange,提问作者Josi Allen

