为了搞清楚Acitivity的生命周期,进一步了解我们需要在什么时候保存需要的信息,我们需要几个视图
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_activity"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_number1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="这是Activity中有id的EditText"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="这是Activity中没有id的EditText"
android:ems="10" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<Button
android:id="@+id/bt_show_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示" />
<Button
android:id="@+id/bt_switch_orientation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="改变屏幕方向" />
</LinearLayout>
</LinearLayout>
如图
注:由于我的AVD模拟器怎么都无法横屏(使用CTRL+F11、CTRL+F12、小键盘7和9都试了,只是把屏幕整体横过来,而没有重新布局),所以我使用一个Button来手动切换横竖屏
在Activity中声明私有变量
private String mText = "显示输入信息";
private TextView mShowText;
private EditText mInput;
private Button mShowTextButton;
private Button mSwitchOrientationButton;//改变屏幕方向的按钮
暂时不管改变屏幕方向的按钮,在onCreate()方法中初始化其他变量并设置监听
mShowText = (TextView) findViewById(R.id.tv_number1);
mInput = (EditText) findViewById(R.id.editText1);
//如果mShowText为空,则显示字符串mText的值
if(TextUtils.isEmpty(mShowText.getText().toString())) {
mShowText.setText(mText);
}
mFragment = new ScreenOrientationFragment();
mShowTextButton = (Button) findViewById(R.id.bt_show_text);
mShowTextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mText = mInput.getText().toString();
mShowText.setText(mText);
}
});
覆盖生命周期方法,先在onCreate()中添加以下代码
Log.d(TAG, "onCreate(Bundle)");
在Activity中添加常量
private static final String TAG = "LifecycleActivity";
覆盖其他生命周期方法
@Override
protected void onStart(){
super.onStart();
Log.d(TAG, "onStart()");
}
@Override
protected void onRestart(){
super.onRestart();
Log.d(TAG, "onRestart()");
}
@Override
protected void onResume(){
super.onResume();
Log.d(TAG, "onResume()");
}
@Override
protected void onPause(){
super.onPause();
Log.d(TAG, "onPause()");
}
@Override
protected void onStop(){
super.onStop();
Log.d(TAG, "onStop()");
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
Log.d(TAG, "onSaveInstanceState(Bundle)");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState(Bundle)");
}
运行程序,当第一次加载活动时,LogCat窗口中可以看到类似以下日志:
07-07 06:27:11.850: D/LifecycleActivity(2360): onCreate(Bundle)
07-07 06:27:12.600: D/LifecycleActivity(2360): onStart()
07-07 06:27:12.600: D/LifecycleActivity(2360): onResume()
进行准备工作:在两个EditText中输入任意内容,再点击“显示”按钮,使TextView中的内容更新为第一个EditText中的值
点击模拟器上的主屏幕按钮,活动进入后台,LogCat
07-07 11:12:23.550: D/LifecycleActivity(2360): onPause()
07-07 11:12:29.710: D/LifecycleActivity(2360): onSaveInstanceState(Bundle)
07-07 11:12:29.710: D/LifecycleActivity(2360): onStop()
再点击应用图标回到应用,LogCat
07-07 11:15:01.330: D/LifecycleActivity(2360): onRestart()
07-07 11:15:01.330: D/LifecycleActivity(2360): onStart()
07-07 11:15:01.350: D/LifecycleActivity(2360): onResume()
可以看到之前输入的信息和TextView中的信息原封不动地还原了。
再来看另外一种情况(模拟系统回收内存销毁activity),先在模拟器中打开Settings,找到Development options选项,勾选Don't keep activities选项
再回到之前的应用活动,重复准备工作的操作,当点击主屏幕按钮后,再来看LogCat
07-07 11:27:44.200: D/LifecycleActivity(2360): onPause()
07-07 11:27:51.730: D/LifecycleActivity(2360): onSaveInstanceState(Bundle)
07-07 11:27:51.730: D/LifecycleActivity(2360): onStop()
07-07 11:27:51.810: D/LifecycleActivity(2360): onDestroy()
注意最后一行,调用了onDestroy()来销毁活动,重新运行应用
07-07 11:30:20.920: D/LifecycleActivity(2360): onCreate(Bundle)
07-07 11:30:22.310: D/LifecycleActivity(2360): onStart()
07-07 11:30:22.410: D/LifecycleActivity(2360): onRestoreInstanceState(Bundle)
07-07 11:30:22.420: D/LifecycleActivity(2360): onResume()
只有设置了id的EditText中的信息被还原了,没有id的EditText中的信息就丢失了。而对于TextView,无论是否有id,系统都不会保存其中的内容(为什么?以后再慢慢研究)。
当屏幕旋转时会发生什么呢?先给“改变屏幕方向”按钮初始化并设置监听
mSwitchOrientationButton = (Button) findViewById(R.id.bt_switch_orientation);
mSwitchOrientationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
});
回到应用,重复准备工作操作,点击“改变屏幕方向”按钮(该按钮只是改变了活动的显示方向,还需要按CTRL+F11使模拟器屏幕方向改变),查看LogCat
07-07 11:51:31.120: D/LifecycleActivity(2360): onPause()
07-07 11:51:31.130: D/LifecycleActivity(2360): onSaveInstanceState(Bundle)
07-07 11:51:31.130: D/LifecycleActivity(2360): onStop()
07-07 11:51:31.130: D/LifecycleActivity(2360): onDestroy()
07-07 11:51:31.680: D/LifecycleActivity(2360): onCreate(Bundle)
07-07 11:51:32.310: D/LifecycleActivity(2360): onStart()
07-07 11:51:32.310: D/LifecycleActivity(2360): onRestoreInstanceState(Bundle)
07-07 11:51:32.310: D/LifecycleActivity(2360): onResume()
可以看到系统是将活动销毁后再新建一个活动
跟之前的结果一样。
从上面的测试中发现,活动的onSaveInstanceState(Bundle)被调用了,所以在大多数情况下,我们可以在onSaveInstanceState(Bundle)方法中保存我们需要的数据。
但是和单击主屏幕不一样的是,单击后退按钮时,无论是否勾选Don't keep activities,系统总是会销毁当前activity,看LogCat
07-07 13:12:34.990: D/LifecycleActivity(2360): onPause()
07-07 13:12:39.940: D/LifecycleActivity(2360): onStop()
07-07 13:12:39.940: D/LifecycleActivity(2360): onDestroy()
这时直接onDestroy了,而没有调用onSaveInstanceState。所以在点击后退按钮的情况下,再想通过onSaveInstanceState(Bundle)来保存并恢复数据就不太现实了。不过可以在onPause()中,借助数据库或者文件来保存需要的数据。