Activity的生命周期,这是每个Android开发者必须了解的知识。Activity是四大组件之一,而且是使用最频繁的组件。横竖屏切换是每个Android开发者都会遇到的问题。那么横竖屏切换后Activity到底发生了什么呢?
###1、生命周期的变化
建一个Activity,重写所有的生命周期方法,然后在这些方法中添加Log。
public class ActivityA extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
Log.i("axe.mg","onCreate()");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("axe.mg","onRestart()");
}
@Override
protected void onStart() {
super.onStart();
Log.i("axe.mg","onStart()");
}
@Override
protected void onResume() {
super.onResume();
Log.i("axe.mg","onResume()");
}
@Override
protected void onPause() {
super.onPause();
Log.i("axe.mg","onPause()");
}
@Override
protected void onStop() {
super.onStop();
Log.i("axe.mg","onStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("axe.mg","onDestroy()");
}
}
正常启动这个Activity。
09-28 23:16:49.809 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onCreate()
09-28 23:16:49.809 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStart()
09-28 23:16:49.819 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onResume()
通过Log可以看到Activity从创建到展示的的生命周期: onCreate() —>onStart() —>onResume()
进行横竖屏切换。
09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onPause()
09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStop()
09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onDestroy()
09-28 23:17:42.719 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onCreate()
09-28 23:17:42.729 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStart()
09-28 23:17:42.729 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onResume()
通过Log将生命周期分为两部分来分析: 1、Activity销毁: onPause() —> onStop() —> onDestroy() 2、Activity的重新创建展示 :onCreate() —> onStart() —>onResume()
结论:当Activity横竖屏切换时.Activity就会重新创建。 横竖屏切换时Activity会被销毁 , onPause() onStop() onDestory() 会被调用。 然后Activity又会被重新创建,onCreate() onStart() onResume() 会被调用。
–
###2、横竖屏切换后的数据恢复 已经知道Activity横竖屏切换时Activity会重新创建。那么如何恢复重建前的数据呢? Activity中有两个方法用来保存和恢复Activity重建前的数据:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
onSaveInstanceState:横竖屏切换时,Activity销毁前系统会调用onSaveInstanceState通过保存Bundle参数来保存当前的Activity的数据。这个方法会在onStop前调用。
onRestoreInstanceState:当Activity被重新创建之后会调用onRestoreInstanceState,并把Activity销毁时 onSaveInstanceState方法所保留的数据作为Bundle参数同时传递给onRestoreInstanceState和onCreate方法。所以我们可以在onRestoreInstanceState和onCreate方法中看到两个一样的参数Bundle savedInstanceState。这个方法会在onStart后调用。
强调一点:必须是Activity异常情况下被终止(例如:横竖屏切换)才会调用这两个方法。
通过代码验证:在Activity中重写onSaveInstanceState和onRestoreInstanceState来保存和恢复Activity重建前的数据。
在onSaveInstanceState保存一个“value_string”的string 在onRestoreInstanceState获取“value_string”这个值。
public class ActivityA extends Activity {
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("key","value_string");
Log.i("axe.mg","onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String str = savedInstanceState.getString("key");
Log.i("axe.mg","onRestoreInstanceState");Log.i("axe.mg","get value:"+str);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
Log.i("axe.mg","onCreate()");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("axe.mg","onRestart");
}
@Override
protected void onStart() {
super.onStart();
Log.i("axe.mg","onStart()");
}
@Override
protected void onResume() {
super.onResume();
Log.i("axe.mg","onResume()");
}
@Override
protected void onPause() {
super.onPause();
Log.i("axe.mg","onPause()");
}
@Override
protected void onStop() {
super.onStop();
Log.i("axe.mg","onStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("axe.mg","onDestroy()");
}
横竖屏后获取到的Log。
09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onPause()
09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onSaveInstanceState
09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onStop()
09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onDestroy()
09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onCreate()
09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onStart()
09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onRestoreInstanceState
09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: get value:value_string
09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onResume()
通过Log来分析: 1、Activity销毁,调用onSaveInstanceState,在onSaveInstanceState方法里面 通过outState.putString(“key”,”value_string”);保存了“value_string”这个值。
2、Activity重建,调用onRestoreInstanceState,在onSaveInstanceState方法里面 通过savedInstanceState.getString(“key”);获取出了“value_string”这个值。
###3、如何防止横竖屏切换时Activity重建
可能在开发中并不希望横竖屏切换后Activity重建。此时需要配置configChange参数, 可以设置: android:configChanges=”orientation|screenSize”
<activity
android:name=".develop.ActivityA"
android:label="@string/app_name"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
配置添加android:configChanges=”orientation|screenSize” (跟踪framework层代码,是由于google在android3.2中添加了screensize改变的通知,在转屏的时候,不仅是orientation发生了改变,screensize同样也发生了改变所以要添加“screenSize”) 这种情况下横竖屏切换后不再重建Activity。同时会调用如下方法:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
通过代码验证: Activity添加android:configChanges=”orientation|screenSize”
<activity
android:name=".develop.ActivityA"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
public class ActivityA extends Activity {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("axe.mg","onConfigurationChanged");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("key","value_string");
Log.i("axe.mg","onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String str = savedInstanceState.getString("key");
Log.i("axe.mg","onRestoreInstanceState");Log.i("axe.mg","get value:"+str);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
Log.i("axe.mg","onCreate()");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("axe.mg","onRestart");
}
@Override
protected void onStart() {
super.onStart();
Log.i("axe.mg","onStart()");
}
@Override
protected void onResume() {
super.onResume();
Log.i("axe.mg","onResume()");
}
@Override
protected void onPause() {
super.onPause();
Log.i("axe.mg","onPause()");
}
@Override
protected void onStop() {
super.onStop();
Log.i("axe.mg","onStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("axe.mg","onDestroy()");
}
横竖平切换后:
09-29 00:54:00.849 21338-21338/com.mg.axe.androiddevelop I/axe.mg: onConfigurationChanged
通过Log分析: 此时Activity不再重建, 不会调用生命周期的方法,也不会调用onSaveInstanceState和onRestoreInstanceState。会调用onConfigurationChanged方法。
+++++++++附件信息:configChanges属性的值+++++++++++
通过设置这个属性可以使Activity捕捉设备状态变化,以下是可以被识别的内容: 设置方法:将下列字段用“|”符号分隔开,例如:“locale|navigation|orientation
“mcc” 国际移动用户识别码所属国家代号是改变了—– sim被侦测到了,去更新mcc mcc是移动用户所属国家代号 “mnc” 国际移动用户识别码的移动网号码是改变了—— sim被侦测到了,去更新mnc MNC是移动网号码,最多由两位数字组成,用于识别移动用户所归属的移动通信网 “locale” 地址改变了—–用户选择了一个新的语言会显示出来 “touchscreen” 触摸屏是改变了——通常是不会发生的 “keyboard” 键盘发生了改变—-例如用户用了外部的键盘 “keyboardHidden” 键盘的可用性发生了改变 “navigation” 导航发生了变化—–通常也不会发生 “screenLayout” 屏幕的显示发生了变化——不同的显示被激活 “fontScale” 字体比例发生了变化—-选择了不同的全局字体 “uiMode” 用户的模式发生了变化 “orientation” 屏幕方向改变了 “screenSize” 屏幕大小改变了 “smallestScreenSize” 屏幕的物理大小改变了,如:连接到一个外部的屏幕上
参考链接: http://www.cnblogs.com/-cyb/articles/Android_onConfigurationChanged.html (要添加screenSize的问题) http://www.cnblogs.com/carlo/p/4311010.html (附件信息:configChanges属性的值)
参考书籍:Android开发艺术探索。