记得当初面试的遇到两个题目:写出横屏切换竖屏Activity的生命周期和A跳转到B的完整生命周期。当时凭着自己的理解答了,于是乎CTO微微一笑:我不评论对错,你有时间自己去运行验证验证……直到最近自己在项目中又遇到了,困扰了蛮久才发现原因,便想总结下(在版本Android 6.0的基础上),毕竟好记性不如烂笔头,何况我的记忆力已经大不如前啦。
例:MainActivity 跳转至 ToActivity,再从ToActivity跳转至MainActivity的完整生命周期,首先看看标准模式下
首先新建MainActivity,
onCreate()——>onStart()——>onResume()——>
跳转至 ToActivity(跳转可以分为两个步骤,第一个步骤先隐藏MainActivity,再创建ToActivity),
MainActivity的onPause()——>ToActivity的onCreate()——>
ToActivity的onRestart()——>ToActivity的onResume()——>
MainActivity的onSaveInstanceState()——>MainActivity的onStop()——>
从ToActivity跳转回MainActivity,
ToActivity的onPause()——>MainActivity的onCreate()——>
MainActivity的onRestart()——>MainActivity的onResume()——>
ToActivity的onSaveInstanceState()——>ToActivity的onStop()——>
从ToActivity按返回键返回MainActivity(与跳转不同的是返回是会把ToActivity finish掉),
ToActivity的onPause()——>MainActivity的onCreate()——>
MainActivity的onRestart()——>MainActivity的onResume()——>
ToActivity的onSaveInstanceState()——>ToActivity的onStop()——>
ToActivity的onDestory()
onPause()——>onSaveInstanceState()——>onStop()
onRestart()——>onStart()——>onResume()
经验证Activity跳转时的生命周期变化,与android:configChanges 和 android:lunchMode的取值无关(由于篇幅问题截图不一一贴出)。
第一次新建MainActivity
跳转至 ToActivity
从ToActivity跳转回MainActivity
从ToActivity按返回键返回MainActivity
在MainActivity锁屏时(按Home键也是一样)
解锁返回到MainActivity
onConfigurationChanged事件是在改变屏幕方向、弹出软件盘和隐藏软键盘时,不再去重新触发Activity的onCreate()方法,而是直接执行onConfigurationChanged()方法;有些情况下,当横、竖屏转换时,程序会报错或异常终止,往往是由于重新触发了Activity的生命周期方法。进而造成重复的初始化工作,影响程序效率等等。所以我们合理地在代码中捕获相关事件并进行逻辑处理提高我们的程序的健壮性和高效性。
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(MainActivity.this, "现在是竖屏", Toast.LENGTH_SHORT).show();
Log.d(TAG, "竖屏"+"onConfigurationChanged by MainActivity");
}
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(MainActivity.this, "现在是横屏", Toast.LENGTH_SHORT).show();
Log.d(TAG, "横屏"+"onConfigurationChanged by MainActivity");
}
}
在MainActivity 由竖屏切换为横屏时
在MainActivity 由横屏切换为竖屏时
在低版本中想捕获横竖屏切换的事件,得先申请权限( Android:name=”android.permission.CHANGE_CONFIGURATION”)
在高版本里直接在清单文件里配置orientation即可,需要注意的是从Android 3.2(API 13)起,ScreenSize也随着设备的横竖切换而改变。
所以,在AndroidManifest.xml里设置的MiniSdkVersion和 TargetSdkVersion属性大于等于13的情况下,如果你想阻止程序在运行时重新加载Activity,除了设置”orientation”,你还必须设置”ScreenSize”,否则还是无法在onConfigurationChanged里捕捉到相应事件。
在MainActivity 由竖屏切换为横屏时
onPause()——>onSaveInstanceState()——>onStop()——> onDestory()——>onCreate()——>onStart()——> onRestoreInstanceState()——>onResume()
onPause()——>onSaveInstanceState()——>onStop()——> onDestory()——>onCreate()——>onStart()——> onRestoreInstanceState()——>onResume()
activity在有“被销毁的可能”时,就会调用onSaveInstanceState方法,给你一个机会去保存activity中的数据,之后横竖屏切换时activity确实在“未经你许可的情况下被销毁了”,所以系统又会调用onRestoreInstanceState方法,让你把之前保存的数据恢复
假如软件在横竖屏之间切换,由于横竖屏的高宽会发生变化,有可能会要求不同的布局。可通过以下两种方法来切换布局:
在res目录下建立layout-land和layout-port目录,相应的layout文件名不变,比如:layout-land是横屏的layout,layout-port是竖屏的layout,其他的不用管,横竖屏切换时程序调用Activity的onCreate方法中的setOnContent(xxx),系统会自动加载相应的布局。
因为当屏幕变为横屏的时候,系统会重新加载当前Activity的onCreate方法(如果不设置Activity的android:configChanges属性的话),可以把代码判断屏幕方向,再设置调入不同的layout。
/** 1:竖屏 2:横屏 判断屏幕以旋转的方向 */
private int orientation;
orientation=getResources().getConfiguration().orientation;
//横屏显示设置
android:screenOrientation="lanscape"
//竖屏显示设置
android:screenOrientation="portrait"
在没有配置android:configChanges时,android屏幕的切换会重启Activity,所以在Activity销毁前保存当前活动的状态,并在Activity再次Create的时候载入配置
android:screenOrientation="sensor" android:configChanges="orientation|screenSize|keyboardHidden"
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if (width > height) {
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; // 横屏
} else {
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; // 竖屏
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
this.setRequestedOrientation(orientation);
}
但是这样的话你切到别的画面的时再返回到原画面,它仍然是横的或竖的。怎么让它从别的屏幕回来后,又重新横竖屏布局呢?
只要在onResume()中在设定下就行了(但是这个仅仅只是支持横竖屏只有一个layout的)
@Override
protected void onResume() {
orientation = ActivityInfo.SCREEN_ORIENTATION_USER;
this.setRequestedOrientation(orientation);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if (width > height) {
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
super.onResume();
}