Android 横竖屏切换小结(实践)
首先我们先创建一个Activity 名为Main2Activity 写出相应的Activity 的生命周期,并且在Androidmanifest.xm中什么都没有配置如下:
<activity android:name=".land_portrait.Main2Activity"></activity>
- 首先测试下不设置方向时横竖屏切换走的生命周期,手机开启自动旋转屏幕如下:
- 以下测试用的真机HTC 5.0
- 看下启动后的生命周期(onCreate() ——onStart()——onResume())
02-01 10:28:25.418 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onCreate()
02-01 10:28:25.418 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStart()
02-01 10:28:25.418 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onResume()
- 看下从竖屏切换到横屏的生命周期(onPause()—— onStop()——onDestroy()——onCreate()——onStart()——onResume()):
02-01 10:29:27.444 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onPause()
02-01 10:29:27.444 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStop()
02-01 10:29:27.444 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onDestroy()
02-01 10:29:27.534 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onCreate()
02-01 10:29:27.534 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStart()
02-01 10:29:27.545 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onResume()
- 接下来再看下从横屏切换到竖屏的生命周期(onPause()——onStop()——onDestroy()——onCreate()——onStart()——onResume()):
02-01 10:31:52.900 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onPause()
02-01 10:31:52.900 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStop()
02-01 10:31:52.900 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onDestroy()
02-01 10:31:52.980 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onCreate()
02-01 10:31:52.980 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStart()
02-01 10:31:52.980 25737-25737/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onResume()
- 从上面看出在什么属性都不设置的情况下,横竖屏切换都只执行了一次,并且过程一样。
- 测试只设置android:configChanges=”orientation|keyboardHidden” 横竖屏切换只执行了一次
- 测试只设置android:configChanges=”orientation” 横竖屏切换只执行了一次
- 总结对于不设置android:configChanges或者设置android:configChanges=”orientation”或者设置了android:configChanges=”orientation|keyboardHidden” 横竖屏切换都执行一次。
下面来介绍下android:configChanges
下面介绍下设置横竖屏的方法:
android:configChanges
列出 Activity 将自行处理的配置更改。在运行时发生配置更改时,默认情况下会关闭 Activity 然后将其重新启动,但使用该属性声明配置将阻止 Activity 重新启动。 Activity 反而会保持运行状态,并且系统会调用其 onConfigurationChanged() 方法。
注:应避免使用该属性,并且只应在万不得已的情况下使用。 如需了解有关如何正确处理配置更改所致重新启动的详细信息,请阅读处理运行时变更。
任何或所有下列字符串均是该属性的有效值。多个值使用“|”分隔 — 例如,“locale|navigation|orientation”。
值 | 说明 |
---|---|
“mcc” | IMSI 移动国家/地区代码 (MCC) 发生了变化 - 检测到了 SIM 并更新了 MCC。 |
“mnc” | IMSI 移动网络代码 (MNC) 发生了变化 - 检测到了 SIM 并更新了 MNC。 |
“locale” | 语言区域发生了变化 — 用户为文本选择了新的显示语言。 |
“touchscreen” | 触摸屏发生了变化。(这种情况通常永远不会发生。) |
“keyboard” | 键盘类型发生了变化 — 例如,用户插入了一个外置键盘。 |
“keyboardHidden” | 键盘无障碍功能发生了变化 — 例如,用户显示了硬件键盘。 |
“navigation” | 导航类型(轨迹球/方向键)发生了变化。(这种情况通常永远不会发生。) |
“screenLayout” | 屏幕布局发生了变化 — 这可能是由激活了其他显示方式所致。 |
“fontScale” | 字体缩放系数发生了变化 — 用户选择了新的全局字号。 |
“uiMode” | 用户界面模式发生了变化 — 这可能是因用户将设备放入桌面/车载基座或夜间模式发生变化所致。 请参阅 UiModeManager。 |
“orientation” | 屏幕方向发生了变化 — 用户旋转了设备。 > 注:如果您的应用面向 API 级别 13 或更高级别(按照 minSdkVersion 和 targetSdkVersion 属性所声明的级别),则还应声明 “screenSize” 配置,因为当设备在横向与纵向之间切换时,该配置也会发生变化。 |
“screenSize” | 当前可用屏幕尺寸发生了变化。它表示当前可用尺寸相对于当前纵横比的变化,因此会在用户在横向与纵向之间切换时发生变化。 不过,如果您的应用面向 API 级别 12 或更低级别,则 Activity 始终会自行处理此配置变更(即便是在 Android 3.2 或更高版本的设备上运行,此配置变更也不会重新启动 Activity)。此项为 API 级别 13 中新增配置。 |
“smallestScreenSize” | 物理屏幕尺寸发生了变化。它表示与方向无关的尺寸变化,因此只有在实际物理屏幕尺寸发生变化(如切换到外部显示器)时才会变化。 对此配置的变更对应于smallestWidth 配置的变化。 不过,如果您的应用面向 API 级别 12 或更低级别,则 Activity 始终会自行处理此配置变更(即便是在 Android 3.2 或更高版本的设备上运行,此配置变更也不会重新启动 Activity)。此项为 API 级别 13 中新增配置。 |
“layoutDirection” | 布局方向发生了变化。例如,从从左至右 (LTR) 更改为从右至左 (RTL)。 此项为 API 级别 17 中新增配置。 |
所有这些配置变更都可能影响应用看到的资源值。 因此,调用 onConfigurationChanged() 时,通常有必要再次获取所有资源(包括视图布局、可绘制对象等),以正确处理变化。|
android:screenOrientation
Activity 在设备上的显示方向。如果 Activity 是在多窗口模式下运行,系统会忽略该属性。
其值可以是下列任一字符串:
Tables | Are |
---|---|
“unspecified” | 默认值。由系统选择方向。在不同设备上,系统使用的政策以及基于政策在特定上下文所做的选择可能有所差异。 |
“behind” | 与 Activity 栈中紧接着它的 Activity 的方向相同。 |
“landscape” | 横向方向(显示的宽度大于高度)。 |
“portrait” | 纵向方向(显示的高度大于宽度)。 |
“reverseLandscape” | 与正常横向方向相反的横向方向。API 级别 9 中的新增配置。 |
“reversePortrait” | 与正常纵向方向相反的纵向方向。API 级别 9 中的新增配置。 |
“sensorLandscape” | 横向方向,但根据设备传感器,可以是正常或反向的横向方向。API 级别 9 中的新增配置。 |
“sensorPortrait” | 纵向方向,但根据设备传感器,可以是正常或反向的纵向方向。API 级别 9 中的新增配置。 |
“userLandscape” | 横向方向,但根据设备传感器和用户的传感器首选项,可以是正常或反向的横向方向。 如果用户锁定了基于传感器的旋转,其行为与 landscape 相同,否则,其行为与 sensorLandscape 相同。API 级别 18 中的新增配置。 |
“userPortrait” | 纵向方向,但根据设备传感器和用户的传感器首选项,可以是正常或反向的纵向方向。 如果用户锁定了基于传感器的旋转,其行为与 portrait 相同,否则,其行为与 sensorPortrait 相同。API 级别 18 中的新增配置。 |
“sensor” | 方向由设备方向传感器决定。显示方向取决于用户如何手持设备,它会在用户旋转设备时发生变化。 但一些设备默认情况下不会旋转到所有四种可能的方向。要允许全部四种方向,请使用 “fullSensor”。 |
“fullSensor” | 方向由 4 种方向中任一方向的设备方向传感器决定。这与 “sensor” 类似,不同的是它允许所有 4 种可能的屏幕方向,无论设备正常情况下采用什么方向(例如,一些设备正常情况下不使用反向纵向或反向横向,但它支持这些方向)。 API 级别 9 中的新增配置。 |
“nosensor” | 决定方向时不考虑物理方向传感器。传感器会被忽略,因此显示不会随用户对设备的移动而旋转。 除了这个区别,系统在选择方向时使用的政策与“unspecified”设置相同。 |
“user” | 用户当前的首选方向。 |
“fullUser” | 如果用户锁定了基于传感器的旋转,其行为与 user 相同,否则,其行为与 fullSensor 相同,允许所有 4 种可能的屏幕方向。 API 级别 18 中的新增配置。 |
“locked” | 将方向锁定在其当前的任意旋转方向。API 级别 18 中的新增配置。 |
注:如果您声明其中一个横向或纵向值,系统将其视为对 Activity 运行方向的硬性要求。 因此,您声明的值支持通过 Google Play 之类的服务进行过滤,这样就能将您的应用只提供给支持 Activity 所要求方向的设备。 例如,如果您声明了 “landscape”、”reverseLandscape” 或 “sensorLandscape”,则您的应用将只提供给支持横向方向的设备。 不过,您还应通过 元素明确声明,您的应用要求采用纵向或横向方向。 例如,。这纯粹是 Google Play(以及其他支持它的服务)提供的一种过滤行为,平台本身并不能控制当设备仅支持特定方向时您的应用能否安装。
而我们经常在其他地方看到的结论如下:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
- 所以是什么原因导致我们的结论不一样呢?
需要说明的是: 我的测试环境是 targetSdkVersion 26,测试手机HTC是 系统API 5.0!
查看官方文档,发现有如下提示:
注意:从 Android 3.2(API 级别 13)开始,当设备在纵向和横向之间切换时,“屏幕尺寸”也会发生变化。因此,在开发针对 API
级别 13 或更高版本系统的应用时,若要避免由于设备方向改变而导致运行时重启(正如 minSdkVersion 和
targetSdkVersion 属性中所声明),则除了”orientation”值以外,您还必须添加
“screenSize”值。即,您必须声明
android:configChanges=”orientation|screenSize”。但是,如果您的应用是面向 API 级别 12
或更低版本的系统,则 Activity 始终会自行处理此配置变更(即便是在 Android 3.2
或更高版本的设备上运行,此配置变更也不会重启 Activity)。
下面再来测试下配置 android:configChanges=”orientation|keyboardHidden|screenSize”
- 由竖屏到横屏运行日志:
02-01 11:26:45.123 22871-22871/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onConfigurationChanged
- 由横屏切换到竖屏运行日志:
02-01 11:28:09.553 22871-22871/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onConfigurationChanged
结论: 从 API 13开始,配置 android:configChanges=”orientation|keyboardHidden|screenSize”,才不会销毁 activity,且只调用 onConfigurationChanged方法。
小结
从 Android 3.2 (API级别 13)开始
1、不设置Activity的android:configChanges,或者设置Activity的android:configChanges=”orientation”,或者设置Activity的android:configChanges=”orientation|keyboardHidden”,切换屏会重新调用各个生命周期,切横竖屏时会执行一次,切竖屏时会执行一次。
2、只有配置了andrioid:configChanges=”orientation|keyboardHidden|ScreenSize”才不会销毁actvity,且只调用onConfigurationChanged方法。注意:keyboardHidden属性可以不加,这个是隐藏软键盘的。
代码中设置横竖屏切换
在代码中切换屏幕的方向主要调用 setRequestedOrientation(int requestedOrientation) 方法,此方法的作用等同于在 AndroidManifest.xml设置Activity 的android:screenOrientation,所以,其可传递的参数如 android:screenOrientation表格中一样。
设置横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
设置竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
通过Button设置横竖屏切换
switch (v.getId()) {
case R.id.button:
//判断当前屏幕方向
if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//切换竖屏
Main2Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
//切换横屏
Main2Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
break;
}
非重启模式即设置了 android:configChanges=”orientation|screenSize”日志如下:
02-01 16:04:26.201 11917-11917/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onConfigurationChanged ()
重启模式即没有设置 android:configChanges=”orientation|screenSize” 日志如下:
02-01 16:09:07.221 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onPause()
02-01 16:09:07.221 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStop()
02-01 16:09:07.221 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onDestroy()
02-01 16:09:07.341 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onCreate()
02-01 16:09:07.351 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onStart()
02-01 16:09:07.351 16492-16492/devstrongzhao.activitylaunchmode I/devstrongzhao.activitylaunchmode.land_portrait.Main2Activity: onResume()
设置横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
设置竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
注意: 通过 setRequestedOrientation(int requestedOrientation)
修改了屏幕方向后,就类似于设置了android:screenOrientation,效果是一样的,比如:调用setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),无论屏幕怎么旋转,都不会切换屏幕方向。如果要恢复为响应横竖屏随物理方向传感器设备变换,那么就需要手动调用类似setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);代码进行恢复。
横竖屏切换我们需要做什么
重启模式:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里,当Acivity第一次被创建的时候为空
//所以我们需要判断一下
if( savedInstanceState != null ){
savedInstanceState.getString("anAnt");
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("anAnt","Android");
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String myString = savedInstanceState.getString("anAnt");
}
补充一点: 如果大家在资源目录res 中添加了 layout-land(横向布局文件夹) 和 layout-port (竖想布局文件夹),重启Activity模式的横竖屏切换,系统会自动帮我们显示正确方向的布局UI。
非重启模式下:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//如果需要可以更改布局
} else {
Log.i(this.getClass().getName(), "onConfigurationChanged");
}
}
/**
* 判断是否平板设备
* @param context
* @return true:平板,false:手机
*/
private boolean isTabletDevice(Context context) {
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
希望点赞!!!!!!!!!!!