Android横竖屏切换小结
来源:互联网 发布:程序员刷题书籍推荐 编辑:程序博客网 时间:2024/06/05 08:12
Android开发中,大多APP可能根据实际情况直接将APP的界面方向设死了,或竖屏或横屏。但是,我们还是会遇到横竖屏切换的功能需求,不管是通过物理重力感应触发,还是用户手动触发。所以,我们有必要去弄清楚Android中横竖屏切换到底做了什么。
一、android:screenOrientation & android:configChanges
- android:screenOrientation
是用来设置 activity在设备上的显示方向的,只能是下面的唯一值:
如果你上传应用到 Google Play,需要注意以下提示:
Note: When you declare one of the landscape or portrait values, it is considered a hard requirement for the orientation in which the activity runs. As such, the value you declare enables filtering by services such as Google Play so your application is available only to devices that support the orientation required by your activities. For example, if you declare either”landscape”, “reverseLandscape”, or “sensorLandscape”, then your application will be available only to devices that support landscape orientation. However, you should also explicitly declare that your application requires either portrait or landscape orientation with the element. For example, . This is purely a filtering behavior provided by Google Play (and other services that support it) and the platform itself does not control whether your app can be installed when a device supports only certain orientations.
* android:configChanges
用来设置 activity配置改变(不仅仅是屏幕方向,还有语言、地区等等)的集合。当一个配置改变在运行中发生时,activity默认情况下会先销毁然后重新创建。但是,如果通过这个属性声明了某个配置后,将可以避免上面的情况,而是依然运行,并回调 onConfigurationChanged() 方法。该属性可以设置多个值:
想了解更多就看官方文档。
二、横竖屏切换对Activity生命周期的影响
通过打印Activity各个生命周期的执行情况,我们根据以下几种情况来分析:
1. 不配置 configChanges
2. 配置 android:configChanges=”orientation”
3. 配置 android:configChanges=”orientation|keyboardHidden”
- 竖屏切横屏
11-02 20:17:44.898 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onPause11-02 20:17:45.008 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onSaveInstanceState11-02 20:17:45.008 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStop11-02 20:17:45.018 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onDestroy11-02 20:17:45.038 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onCreate - orientation11-02 20:17:45.088 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStart11-02 20:17:45.088 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onRestoreInstanceState11-02 20:17:45.088 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onResume
- 横屏切竖屏:
11-02 20:19:00.268 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onPause11-02 20:19:00.268 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onSaveInstanceState11-02 20:19:00.268 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStop11-02 20:19:00.268 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onDestroy11-02 20:19:00.318 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onCreate - orientation11-02 20:19:00.338 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStart11-02 20:19:00.338 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onRestoreInstanceState11-02 20:19:00.338 13324-13324/com.ys.yoosir.screenconfigchange D/MainActivity: -- onResume
从上面的 3种方式配置 打印的 Log (三种方式 Log是一样的,故合并显示),我们可以总结如下:
不设置Activity的android:configChanges时,或 设置Activity的android:configChanges=”orientation”时,或设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次方法。
而我们经常在其他地方看到的结论如下:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
4. 所以是什么原因导致我们的结论不一样呢?
需要说明的是: 我的测试环境是 targetSdkVersion 24,测试模拟器是 系统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)。
我们现在测试第四种配置方式。
5. 配置
android:configChanges="orientation|keyboardHidden|screenSize"
- 竖屏切横屏
11-02 20:44:06.568 7792-7792/com.ys.yoosir.screenconfigchange D/MainActivity: -- onConfigurationChanged
- 横屏切竖屏
11-02 20:44:52.918 7792-7792/com.ys.yoosir.screenconfigchange D/MainActivity: -- onConfigurationChanged
结论: 从 API 13开始,配置 android:configChanges=”orientation|keyboardHidden|screenSize”,才不会销毁 activity,且只调用 onConfigurationChanged方法。
6. 横竖屏切换小结
- (一)、Android 3.2 (API 级别 13)以前
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
2、设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次。
3、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。
注意: 不设置Activity的android:configChanges时,切换竖屏activity的各个生命周期执行两次,有人说是 在API 2.x下,我未测试,大家可以考证下。
- (二)、从 Android 3.2 (API级别 13)开始
1、不设置Activity的android:configChanges,或设置Activity的android:configChanges=”orientation”,或设置Activity的android:configChanges=”orientation|keyboardHidden”,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。
2、配置 android:configChanges=”orientation|keyboardHidden|screenSize”,才不会销毁 activity,且只调用 onConfigurationChanged方法。
三、代码中动态切换横竖屏
在代码中切换屏幕的方向主要调用 setRequestedOrientation(int requestedOrientation) 方法,此方法的作用等同于在 AndroidManifest.xml设置Activity 的android:screenOrientation,所以,其可传递的参数如 android:screenOrientation表格中一样。
示例代码:
findViewById(R.id.btn_click).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d(TAG,"被点击了"); //判断当前屏幕方向 if(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { //切换竖屏 MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); }else{ //切换横屏 MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } }});
非重启Activity模式:即设置了android:configChanges=”orientation|keyboardHidden|screenSize”,Log输出(横竖屏切换一样)
11-03 10:38:33.998 20317-20317/com.ys.yoosir.screenconfigchange D/MainActivity: 被点击了11-03 10:38:34.108 20317-20317/com.ys.yoosir.screenconfigchange D/MainActivity: -- onConfigurationChanged重启Activity模式:即没有设置android:configChanges="orientation|keyboardHidden|screenSize",Log输出(横竖屏切换一样)11-03 10:59:23.268 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: 被点击了11-03 10:59:23.368 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onPause11-03 10:59:23.368 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onSaveInstanceState11-03 10:59:23.368 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStop11-03 10:59:23.368 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onDestroy11-03 10:59:23.428 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onCreate - orientation11-03 10:59:23.458 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStart11-03 10:59:23.458 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onRestoreInstanceState11-03 10:59:23.458 7724-7724/com.ys.yoosir.screenconfigchange D/MainActivity: -- onResume
注意: 通过 setRequestedOrientation(int requestedOrientation) 修改了屏幕方向后,就类似于设置了android:screenOrientation,效果是一样的,比如:调用setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),无论屏幕怎么旋转,都不会切换屏幕方向。如果要恢复为响应横竖屏随物理方向传感器设备变换,那么就需要手动调用类似setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);代码进行恢复。
四、横竖屏切换我们需要做的事
- 重启Activity模式
在重启Activity模式下,横竖屏切换的时候会导致数据丢失,我们可以通过如下代码来保正数据不丢失:
@Overrideprotectedvoid onSaveInstanceState(Bundle outState) { Log.d(TAG," -- onSaveInstanceState"); Log.d(TAG," -- onSaveInstanceState save: name = yoosir,age = 24,handsome = ture"); outState.putString("name","yoosir"); outState.putInt("age",24); outState.putBoolean("handsome",true); super.onSaveInstanceState(outState);}....@Overrideprotectedvoid onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); Log.d(TAG," -- onRestoreInstanceState"); if(savedInstanceState != null) { String name = savedInstanceState.getString("name"); int age = savedInstanceState.getInt("age"); boolean isHandsome = savedInstanceState.getBoolean("handsome"); Log.d(TAG, " -- onRestoreInstanceState get: name = " + name + ",age = " + age + ",handsome = " + isHandsome); }}
横竖屏切换Log 输出:
11-03 12:03:31.678 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onPause11-03 12:03:31.678 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onSaveInstanceState11-03 12:03:31.678 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onSaveInstanceState save: name = yoosir,age = 24,handsome = ture11-03 12:03:31.688 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStop11-03 12:03:31.688 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onDestroy11-03 12:03:31.758 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onCreate - orientation11-03 12:03:31.758 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onCreate get: name = yoosir,age = 24,handsome = true11-03 12:03:31.788 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onStart11-03 12:03:31.788 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onRestoreInstanceState11-03 12:03:31.788 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onRestoreInstanceState get: name = yoosir,age = 24,handsome = true11-03 12:03:31.788 3663-3663/com.ys.yoosir.screenconfigchange D/MainActivity: -- onResume
如上,大家可以看到在 onCreate() 中也是可以拿到我们之前保存的数据的。
补充一点: 如果大家在资源目录res 中添加了 layout-land(横向布局文件夹) 和 layout-port (竖想布局文件夹),重启Activity模式的横竖屏切换,系统会自动帮我们显示正确方向的布局UI。
- 非重启Activity模式
非重启Activity模式下横竖屏切换,我们的Activity 不会销毁重建,数据也不会丢失。但是,如果我们想根据不同的屏幕方向来展示不同UI或做不同的事,应该怎么做呢?直接上代码:
@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Log.d(TAG," -- onConfigurationChanged"); if(newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){ //切换到竖屏 //修改布局文件 setContentView(R.layout.activity_main); //findViewById .... //TODO something Log.d(TAG," -- onConfigurationChanged 可以在竖屏方向 to do something"); }else{ //切换到横屏 //修改布局文件 setContentView(R.layout.activity_main); //findViewById .... //TODO something Log.d(TAG," -- onConfigurationChanged 可以在横屏方向 to do something"); }}
横竖屏切换Log 输出:
11-03 14:56:50.465 28612-28612/com.ys.yoosir.screenconfigchange D/MainActivity: -- onConfigurationChanged11-03 14:56:50.495 28612-28612/com.ys.yoosir.screenconfigchange D/MainActivity: -- onConfigurationChanged 可以在横屏方向 to do something
大家可以看到,在非重启Activity模式下,横竖屏切换修改UI布局文件时,其实挺麻烦的(我是这样的看法,^_~),需要重新初始化一遍UI。不过,不需要我们手动保存数据倒是挺方便的。
五、横竖屏切换对Fragment的影响
打印 Activity 和 Fragment 各个生命周期,并在Activity 的 onCreate() 中添加如下代码:
//是否已经 add 了 Fragmentif(getSupportFragmentManager().findFragmentByTag("child") == null) { Log.d(TAG, " -- onCreate has no child "); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); blankFragment = BlankFragment.newInstance("one", "two"); fragmentTransaction.add(R.id.root_view, blankFragment, "child"); fragmentTransaction.commit();}else{ Log.d(TAG, " -- onCreate has child ");}
- 重建Activity模式
Log: 带有 BlankFragment 即为 Fragment 的打印,其他则为 Activity 的打印
进入Activity的Log: 我们可以关注下第 2 行log——– onCreate has no child
11-03 17:56:19.465 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onCreate - orientation11-03 17:56:19.525 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onCreate has no child 11-03 17:56:19.545 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- newInstance 11-03 17:56:19.545 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onAttach 11-03 17:56:19.545 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onCreate 11-03 17:56:19.545 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onCreateView 11-03 17:56:19.585 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onActivityCreated 11-03 17:56:19.585 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onStart 11-03 17:56:19.585 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onStart11-03 17:56:19.585 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onResume11-03 17:56:19.585 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onResume 11-03 17:57:02.285 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- one btn click 11-03 17:57:05.705 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- two btn click
横竖屏切换的Log:
1、我们关注一下 第17行 onCreate has child ,所以 Fragment 本身是没有被 destroy,它的views 是被destroy 的
2、关注一下 第5、6、19 和 20 行,Fragment 的局部变量数据被销毁了,我们可以在onSaveInstanceState 保存数据,虽然 Fragment 不像 Activity 拥有 onRestoreInstanceState 方法,但是我们可以在 onActivityCreated 中获取之前保存的数据。
11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onPause 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onPause11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onSaveInstanceState11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onSaveInstanceState save: name = yoosir,age = 24,handsome = ture11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onSaveInstanceState 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onSaveInstanceState save str11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onStop 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onStop11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onDestroyView 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onDestroy 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onDetach 11-03 17:57:40.095 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onDestroy11-03 17:57:40.165 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onAttach 11-03 17:57:40.165 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onCreate 11-03 17:57:40.165 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onCreate - orientation11-03 17:57:40.165 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onCreate get: name = yoosir,age = 24,handsome = true11-03 17:57:40.175 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onCreate has child 11-03 17:57:40.175 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onCreateView 11-03 17:57:40.185 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onActivityCreated 11-03 17:57:40.185 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onActivityCreated get 我设置了参数11-03 17:57:40.185 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onStart 11-03 17:57:40.185 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onStart11-03 17:57:40.195 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onRestoreInstanceState11-03 17:57:40.195 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onRestoreInstanceState get: name = yoosir,age = 24,handsome = true11-03 17:57:40.195 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onResume11-03 17:57:40.195 26990-26990/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onResume
- 非重建Activity模式:
横竖屏切换Log(进入Activity的Log 与 重建Activity模式一样 ):横竖屏切换时,Fragment 和 Activity 都只会调用 onConfigurationChanged 方法。
11-03 18:31:21.725 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onConfigurationChanged 11-03 18:31:21.725 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onConfigurationChanged11-03 18:31:21.725 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onConfigurationChanged 可以在横屏方向 to do something11-03 18:31:36.545 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: BlankFragment -- onConfigurationChanged 11-03 18:31:36.545 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onConfigurationChanged11-03 18:31:36.545 27309-27309/com.ys.yoosir.screenconfigchange D/Main2Activity: -- onConfigurationChanged 可以在竖屏方向 to do something
六、其他小技巧
如果我们应用是手机和平板都可用的,且手机的只能是竖屏不可切换,平板的只能是横屏不可切换。首先,我们要区分设备是手机还是平板,然后设置屏幕方向。代码如下:
/** * 判断是否平板设备 * @param context * @return true:平板,false:手机 */private boolean isTabletDevice(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;}//设置屏幕方向private void setScreenOrientation(Context context){ if(!isTabletDevice(context)){ //手机,竖屏 MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); }else{ //平板,横屏 MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }}
两张生命周期图:
原文地址:http://www.jianshu.com/p/dbc7e81aead2
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- ZZNU17级新生周赛第三场
- 网上下载文件完整性验证方法(以Ant为例window版)
- Linux的部分命令
- 如何使用一根网线连接多个路由器?
- 对于数字特征的若干理解
- Android横竖屏切换小结
- contenteditable属性
- ZZNU17级新生周赛第四场
- 通过SVM走进机器学习的世界
- GitHub下载Spring源码,编译成MyEclipse识别的项目
- laravel5.2邮件发送smtp
- Android组件通信
- 欢迎使用CSDN-markdown编辑器
- 文章标题