文档中明确指出“ This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState”。 几个StackOverflow问题concur。
但是我发现这并不完全准确,并且可能会引起误解。 在水平-垂直之间切换方向时,仅 调用onRestoreInstanceState。每当调用onStart时都不会调用它。
我对此simple lab exercise进行了修改,以打印出日志记录,并将mCount保存到包中并显示。
当您按下后退按钮时,会不调用onRestoreInstanceState
,当您按下Home按钮并重新启动时,会返回到主活动否。即使我看到每次(从日志中)都调用了onSaveInstanceState和onStop,但在onStart之后都没有看到相应的onRestoreInstanceState。这是意外的。文档应明确指出,只有在调用onDestroy时,才在onStart之后调用onRestoreInstanceState。 可靠调用时,是否还有其他情况(切换方向除外)?
了解这些用例对于白盒测试很有用。
MainActivity.java
public class MainActivity extends AppCompatActivity {
private int mCount = 0;
private TextView mShowCount;
public static final String EXTRA_MESSAGE =
"com.example.hellotoast.extra.MESSAGE";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mShowCount = (TextView) findViewById(R.id.show_count);
Log.d("MainActivity", "Hello World");
}
public void showToast(View view) {
Toast toast = Toast.makeText(this, R.string.toast_message,
Toast.LENGTH_SHORT);
toast.show();
Intent intent = new Intent(this, HelloCount.class);
intent.putExtra(EXTRA_MESSAGE, mCount);
startActivity(intent);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(EXTRA_MESSAGE, mCount);
super.onSaveInstanceState(outState);
Log.d("MainActivity", "onSaveInstanceState. saved mCount = " + mCount);
}
@Override
public void onRestoreInstanceState(Bundle b) {
super.onRestoreInstanceState(b);
Log.d("MainActivity", "onRestoreInstanceState");
if(b != null) {
mCount = b.getInt(EXTRA_MESSAGE);
Log.d("MainActivity", "onRestoreInstanceState mCount = "+mCount);
mShowCount.setText(Integer.toString(mCount));
}
}
@Override
protected void onStart() {
super.onStart();
Log.d("MainActivity", "onStart");
}
@Override
protected void onStop() {
super.onStop();
Log.d("MainActivity", "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("MainActivity", "onDestroy");
}
public void countUp(View view) {
mCount++;
if (mShowCount != null) {
mShowCount.setText(Integer.toString(mCount));
}
}
}
HelloCount.java
import static com.example.hellotoast.MainActivity.EXTRA_MESSAGE;
public class HelloCount extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("HelloCount", "onCreate");
setContentView(R.layout.activity_hello_count);
TextView tv = findViewById(R.id.helloCount);
int i = getIntent().getIntExtra(EXTRA_MESSAGE,0);
tv.setText(String.valueOf(i));
}
@Override
protected void onStart() {
super.onStart();
Log.d("HelloCount", "onStart");
}
@Override
protected void onStop() {
super.onStop();
Log.d("HelloCount", "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("HelloCount", "onDestroy");
}
}
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hellotoast.MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/button_toast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorPrimary"
android:onClick="showToast"
android:text="@string/button_label_toast"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="#FFFF00"
android:gravity="center_vertical"
android:text="@string/count_initial_value"
android:textAlignment="center"
android:textColor="@color/colorPrimary"
android:textSize="120sp"
android:textStyle="bold"
android:layout_centerHorizontal="true"
android:layout_below="@+id/button_toast"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
/>
<Button
android:id="@+id/button_count"
android:layout_below="@+id/show_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorPrimary"
android:onClick="countUp"
android:text="@string/button_label_count"
android:textColor="@android:color/white" />
</RelativeLayout>
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="156dp"
android:layout_marginEnd="8dp"
android:text="Hello"
android:textColor="#8BC34A"
android:textColorHighlight="#00882A2A"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/helloCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.099" />
</android.support.constraint.ConstraintLayout>
答案 0 :(得分:1)
在方向更改期间也会调用它,但是当您的活动仍在后台时从内存中弹出时,就会调用它。
您的情况是:
按下主屏幕时,您的活动被暂停(onStop
)。回到它时,您会收到onStart
呼叫,无需还原实例。
按下后退出应用程序时,您会收到onDestroy
的呼叫,其中isFinishing()
返回true。当您“回来”时,没有任何要还原的实例,将创建新的活动。
当您暂停活动(如第1点)并将其在后台停留一段时间(最好在其他应用中导航以填充内存)时,系统可能会决定释放您的活动从记忆里。这将导致onSaveInstanceState
和onDestroy
的呼叫,当您回来时,您将得到onCreate
onRestoreInstanceState
。
您可以进入开发人员设置并启用“不要保留活动”选项,这将模拟内存不足的环境,并在将活动置于后台后强制将其迅速销毁。
答案 1 :(得分:1)
文档明确指出“从先前保存的状态重新初始化活动时,在onStart()之后调用此方法,在此处以saveInstanceState给出”。有几个StackOverflow问题。
但是我发现这并不完全准确,并且可能会引起误解。仅在在水平-垂直之间切换方向时才调用onRestoreInstanceState。每当调用onStart时都不会调用它。
文档未声明每次调用onRestoreInstanceState
时都会调用onStart
。正如您自己引用的那样,它清楚地表明是在重新初始化活动的情况下。
我修改了这个简单的实验练习,以打印出日志记录,并将mCount保存到捆绑软件中并显示出来。
当您按下“后退”按钮返回到主“活动”时,或者当您按下“主页”按钮并重新启动时,不会调用onRestoreInstanceState。
这两种情况都不会导致所涉及的活动被杀死,因此无需恢复状态。
即使我看到每次(从日志中)都调用了onSaveInstanceState和onStop,但在onStart之后都没有看到相应的onRestoreInstanceState。这是意外的。
这是完全可以预期的。 onSaveInstanceState
为您提供了机会,可以在您的活动移至后台以防万一被杀死时保存您的状态。无法预先知道是否将其杀死,因此以防万一,总是调用该方法。但是,onRestoreInstanceState
并非如此。在那种情况下,系统会知道您是否正在重新启动同一活动(因此不需要状态还原,因此不调用该方法),或者是否需要从状态中还原(因此调用该方法)。
文档应明确声明只有在调用onDestroy时,才会在onStart之后调用onRestoreInstanceState。
为什么?有什么区别?
是否有其他可靠调用的情况(切换方向除外)?
为什么重要?您不必在意每种情况下都会调用此方法。您应该只关心正确实现它以恢复活动状态。让系统在必要时调用它,而无论调用它的原因为何,您的应用程序都可以正常运行。
答案 2 :(得分:0)
我了解到在以下情况下肯定会调用onRestoreInstanceState:
水平垂直方向的变化。
语言输入更改。
更改为多窗口(无论如何)。
了解这些用例对于白盒测试很有用。