Android onSaveInstanceState onRestoreInstanceState
在本教程中,我们将讨论两种管理应用程序状态的重要方法,即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。
如果不是,我们将使用计数器中的数据还原视图。
请注意,更改方向后,"电话号码"字段为空。