仅在切换水平-垂直方向时才调用onRestoreInstanceState吗-还有其他情况吗?

时间:2019-06-23 19:46:02

标签: android

文档中明确指出“ 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>

Click Hello button to launch HelloCount Activity. pressing count button increments counter HelloCount

3 个答案:

答案 0 :(得分:1)

在方向更改期间也会调用它,但是当您的活动仍在后台时从内存中弹出时,就会调用它。

您的情况是:

  1. 按下主屏幕时,您的活动被暂停onStop)。回到它时,您会收到onStart呼叫,无需还原实例。

  2. 按下后退出应用程序时,您会收到onDestroy的呼叫,其中isFinishing()返回true。当您“回来”时,没有任何要还原的实例,将创建新的活动。

  3. 当您暂停活动(如第1点)并将其在后台停留一段时间(最好在其他应用中导航以填充内存)时,系统可能会决定释放您的活动从记忆里。这将导致onSaveInstanceStateonDestroy的呼叫,当您回来时,您将得到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:

  1. 水平垂直方向的变化。

  2. 语言输入更改。

  3. 更改为多窗口(无论如何)。

了解这些用例对于白盒测试很有用。