从SecondActivity返回时MainActivity的savedInstanceState为null问题
问题描述
我在完成Android基础02.2:Activity生命周期与状态的实践项目时,遇到一个问题:从SecondActivity点击左上角返回键回到MainActivity,或是旋转MainActivity屏幕时,MainActivity都会执行onSaveInstanceState方法并销毁重建。但前者重建时onCreate的savedInstanceState参数为null,导致之前显示的回复内容丢失;后者savedInstanceState正常非空,状态恢复正常。
复现步骤
- 运行应用
- 在MainActivity的EditText输入内容,点击SEND进入SecondActivity
- 在SecondActivity的EditText输入内容,点击REPLY返回,此时MainActivity顶部显示回复内容
- 再次输入内容点击SEND进入SecondActivity
- 点击SecondActivity左上角返回键回到MainActivity
此时MainActivity顶部的回复内容消失,日志显示MainActivity销毁前已执行onSaveInstanceState,但重建时savedInstanceState为null。旋转屏幕时状态恢复正常,请问该问题的原因是什么?
代码片段
MainActivity.java
package com.example.twoactivities; public class MainActivity extends AppCompatActivity { private static final String LOG_TAG = MainActivity.class.getSimpleName(); public static final String EXTRA_MESSAGE = "com.example.android.twoactivities.extra.MESSAGE"; public static final int TEXT_REQUEST = 1; private TextView mReplyHeadTextView; private TextView mReplyTextView; private EditText mMessageEditText; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(LOG_TAG, "-------"); Log.d(LOG_TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMessageEditText = findViewById(R.id.editText_main); mReplyHeadTextView = findViewById(R.id.text_header_reply); mReplyTextView = findViewById(R.id.text_message_reply); if(savedInstanceState != null){ Log.d(LOG_TAG, "enter saveInstance"); boolean isVisible = savedInstanceState.getBoolean("reply_visible"); if(isVisible){ mReplyHeadTextView.setVisibility(View.VISIBLE); mReplyTextView.setText(savedInstanceState.getString("reply_text")); mReplyTextView.setVisibility(View.VISIBLE); } } } public void launchSecondActivity(View view) { Log.d(LOG_TAG, "Button clicked!"); String message = mMessageEditText.getText().toString(); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra(EXTRA_MESSAGE, message); startActivityForResult(intent, TEXT_REQUEST); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); if(requestCode == TEXT_REQUEST){ if(resultCode == RESULT_OK){ String reply = data.getStringExtra(SecondActivity.EXTRA_REPLY); mReplyHeadTextView.setVisibility(View.VISIBLE); mReplyTextView.setText(reply); mReplyTextView.setVisibility(View.VISIBLE); } } } @Override public void onStart(){ super.onStart(); Log.d(LOG_TAG, "onStart"); } @Override protected void onPause() { super.onPause(); Log.d(LOG_TAG, "onPause"); } @Override protected void onRestart() { super.onRestart(); Log.d(LOG_TAG, "onRestart"); } @Override protected void onStop() { super.onStop(); Log.d(LOG_TAG,"onStop"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(LOG_TAG, "onDestroy"); } @Override protected void onResume() { super.onResume(); Log.d(LOG_TAG, "onResume"); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); Log.d(LOG_TAG, "saving Instance"); if(mReplyHeadTextView.getVisibility() == View.VISIBLE){ outState.putBoolean("reply_visible", true); outState.putString("reply_text", mReplyTextView.getText().toString()); } } }
SecondActivity.java
package com.example.twoactivities; public class SecondActivity extends AppCompatActivity { public static final String LOG_TAG = SecondActivity.class.getSimpleName(); public static final String EXTRA_REPLY = "com.example.android.twoactivities.extra.REPLY"; private EditText mReply; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(LOG_TAG, "-------"); Log.d(LOG_TAG, "Sec onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mReply = findViewById(R.id.editText_second); Intent intent = getIntent(); String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); TextView textView = findViewById(R.id.text_message); textView.setText(message); } public void returnReply(View view) { String reply = mReply.getText().toString(); Intent replyIntent = new Intent(); replyIntent.putExtra(EXTRA_REPLY, reply); setResult(RESULT_OK, replyIntent); finish(); Log.d(LOG_TAG, "End SecondActivity"); } @Override public void onStart(){ super.onStart(); Log.d(LOG_TAG, "Sec onStart"); } @Override protected void onPause() { super.onPause(); Log.d(LOG_TAG, "Sec onPause"); } @Override protected void onRestart() { super.onRestart(); Log.d(LOG_TAG, "Sec onRestart"); } @Override protected void onStop() { super.onStop(); Log.d(LOG_TAG,"Sec onStop"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(LOG_TAG, "Sec onDestroy"); } @Override protected void onResume() { super.onResume(); Log.d(LOG_TAG, "Sec onResume"); } }
问题原因
核心原因是系统仅在「被动销毁Activity(为后续重建做准备)」的场景下,才会传递savedInstanceState给重建的Activity,具体区分两种场景:
- 旋转屏幕(配置变更):系统因为屏幕方向变化临时销毁MainActivity,之后会主动重建它,所以会把之前通过
onSaveInstanceState保存的Bundle传递给onCreate,状态恢复正常。 - 点击返回键回到MainActivity:当你从SecondActivity返回时,如果MainActivity之前因为进入后台被系统销毁(比如内存不足),此时系统重建MainActivity,但用户的返回操作属于「主动结束流程」,系统认为不需要恢复之前的状态,因此不会把之前保存的
savedInstanceState传递给onCreate,导致参数为null。
另外需要注意:只要Activity进入后台(比如启动另一个Activity),系统都会调用onSaveInstanceState保存状态,但这个状态是否会在重建时被复用,完全取决于Activity被销毁的原因——只有系统触发的、需要后续重建的销毁,才会传递该Bundle;用户主动触发的销毁(返回键、调用finish())则不会。
内容的提问来源于stack exchange,提问作者AndroidNewbie
相关产品推荐
相关产品推荐

