Android onSaveInstanceState onRestoreInstanceState

时间:2020-02-23 14:29:07  来源:igfitidea点击:

在本教程中,我们将讨论两种管理应用程序状态的重要方法,即onSaveInstanceState和onRestoreInstanceState。
我们将开发一个Counter Android应用程序,当配置更改时,我们将其中处理应用程序的状态。

Android生命周期

以下是我们应用程序中活动的生命周期:

每当进行配置更改(例如轮换或者应用程序进入多窗口模式)时,都会重新创建活动。

在这种娱乐中,应用程序将重新启动,如果处理不当,可能会丢失视图中的数据。

为此,有两种方法在生命周期的不同阶段触发:

  • onSaveInstanceState
  • onRestoreInstanceState

它们用于保存和检索值。
这些值以键值对的形式存储。
让我们分别看看它们。

onSaveInstanceState

通常在调用onStop()之前/之后调用onSaveInstanceState方法。
视Android版本而异。
在旧版本中,它通常是在onStop()之前获得的。

在此方法内部,我们以键值对的形式将重要值保存在Bundle中。

onSaveInstanceState方法如下所示:

@Override
  public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
  }

在outState捆绑实例上,我们添加键值对。
以下是适用的方法:

我们可以通过将类设置为Parcelable或者Serializable来传递自定义类实例。

让我们看一个使用Parcelable的示例,因为它比Serializable更快。

以下是一个自定义类:

public class Model implements Parcelable {
      public long id;
      public String name;

      public Model(long id, String name) {
          this.id = id;
          this.name = name;
      }

      protected Model(Parcel in) {
          id = in.readLong();
          name = in.readString();
      }

      public final Creator<Model> CREATOR = new Creator<Model>() {
          @Override
          public Model createFromParcel(Parcel in) {
              return new Model(in);
          }

          @Override
          public Model[] newArray(int size) {
              return new Model[size];
          }
      };

      @Override
      public int describeContents() {
          return 0;
      }

      @Override
      public void writeToParcel(Parcel parcel, int i) {
          parcel.writeLong(id);
          parcel.writeString(name);
      }
  }

writeToParcel方法是我们在Parcelable实例上设置类属性的地方。

现在创建模型的实例并将其保存在onSaveInstanceState中。

Model model = new Model(10, "Hello");

@Override
  public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      outState.putParcelable("parcelable", model);
  }

现在我们可以在onRestoreInstanceState方法中检索这些保存的值。

注意:每当您在应用程序中按下主屏幕按钮时,也会调用onSaveInstanceState。

另一个注意事项:只要您在视图上设置了ID,诸如EditText之类的内容就可以隐式保存和恢复其内容。
活动将自动从"视图"层次结构中的每个单个"视图"收集"视图的状态"。

onRestoreInstanceState

仅当在onSaveInstanceState方法中保存了某些内容时,才会触发此方法。
它在onStart()之后被调用。

@Override
  protected void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
      Model model = savedInstanceState.getParcelable("parcelable");
  }

以下是可用的其他方法:

超级方法实现可还原视图层次结构。

通常," onRestoreInstanceState"现在不经常用于恢复值。
可以通过onCreate方法中的Bundle完成相同的操作。
另外,由于始终会先调用onCreate方法,因此,仅在此处还原保存的实例是一种好习惯。

在下一节中,我们将创建一个计数器应用程序,其中使用上述方法保存计数器的状态。

代码

下面给出了" activity_main.xml"的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_margin="16dp"
  android:orientation="vertical"
  tools:context=".MainActivity">

  <EditText
      android:id="@+id/inName"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="Username" 

  <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="Phone number"
      android:inputType="phone" 

  <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="0"
      android:textSize="32sp" 

  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="COUNT UP" 

</LinearLayout>

在以上布局中,第二个EditText没有设置任何ID。
因此,当设备旋转或者发生任何导致活动重新创建的配置时,此EditText内容将被重置。

MainActivity.java的代码如下:

package com.theitroad.androidsaverestoreinstance;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

  Button button;
  TextView textView;
  int counter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      if (savedInstanceState != null) {
          String message = savedInstanceState.getString("message");
          Toast.makeText(this, message, Toast.LENGTH_LONG).show();

          counter = savedInstanceState.getInt("counter", 0);
      }

      button = findViewById(R.id.button);
      textView = findViewById(R.id.textView);
      textView.setText(String.valueOf(counter));

      button.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              counter = Integer.valueOf(textView.getText().toString()) + 1;
              textView.setText(String.valueOf(counter));
          }
      });
  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      outState.putString("message", "This is a saved message");
      outState.putInt("counter", counter);
  }

  @Override
  protected void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
      Toast.makeText(getApplicationContext(), "onRestoreInstanceState", Toast.LENGTH_SHORT).show();
      counter = savedInstanceState.getInt("counter", 0);

  }

}

在这种情况下,保存计数器的整数值,然后在重新创建活动时,再次调用onCreate。
在那边,我们检查saveInstanceStateState Bundle是否为null。
如果不是,我们将使用计数器中的数据还原视图。

请注意,更改方向后,"电话号码"字段为空。