Android横竖屏切换引起问题的小结
来源:互联网 发布:快递打印软件免费版 编辑:程序博客网 时间:2024/05/29 13:11
Android横竖屏切换引起问题的小结
版权声明:我不生产博客,我只是博客的搬运工。
目录(?)[+]
- Android横竖屏切换引起问题的小结
- 所引起的问题
- 解决的方法
- 禁止APP内横竖屏切换
- 重启Activity的横竖屏切换的处理
- 非重启Activity的横竖屏切换的处理
- 结尾
Android横竖屏切换引起问题的小结
终于下定决心好好写(抄)写(抄)属于自己的博客了,以前总是懒惰,总是不肯行动,要知道这个世界永远不会为你而改变,我们只有改变自己。碎语少说,言归正传。
关于Android应用横竖屏的切换所引起的问题以及解决的方法,我以前老大也曾不止一次问过我,而我却从没有认真思考、回答过他,现在我借此做个总结。
1.所引起的问题
1、不设置Activity的Android: configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
2、设置Activity的android: configChanges=“orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次。
3、设置Activity的android: configChanges=“orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfiguration方法
因此,如果放任应用得横竖屏切换而不管的话,首先Activity每次横竖屏切换(包括用setRequestedOrientation调用)都会重新调用一轮onPause-> onStop-> onDestory-> onCreate->onStart->onResume操作,从而销毁原来的Activity对象,创建新的Activity对象,造成内存得开销;另外,如果在刷新界面得事后没有保存用户数据很可能导致数据得丢失。
2.解决的方法
1.禁止APP内横竖屏切换
我入职得第一家公司是主营平板业务,所以大部分应用为了避免麻烦直接禁止了应用得横竖屏切换,very good。具体做法如下:
android:screenOrientation="portrait"
则无论手机如何变动,拥有这个属性的activity都将是竖屏显示。
android:screenOrientation="landscape"
,为横屏显示。
上述修改也可以在Java代码中通过类似如下代码来设置
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
另外android:screenOrientation属性,他有以下几个参数:
“unspecified”:默认值 由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向.
“landscape”:横屏显示(宽比高要长)
“portrait”:竖屏显示(高比宽要长)
“user”:用户当前首选的方向
“behind”:和该Activity下面的那个Activity的方向一致(在Activity堆栈中的)
“sensor”:有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换。
“nosensor”:忽略物理感应器,这样就不会随着用户旋转设备而更改了(”unspecified”设置除外)。
2.重启Activity的横竖屏切换的处理
1)在res目录下建立layout-land和layout-port目录,相应的layout文件名不变,比如main.xml。layout-land是横屏的layout,layout-port是竖屏的layout,其他的不用管,横竖屏切换时程序自己会调用Activity的onCreate方法,从而根据当前横竖屏情况自动加载响应的布局。
2)假如布局资源是不一样又不按照如上设置,则需要通过java代码来判断当前是横屏还是竖屏然后来加载相应的xml布局文件(比如mainP为竖屏mainL为横屏)。因为当屏幕变为横屏的时候,系统会重新呼叫当前Activity的onCreate方法,你可以把以下方法放在你的onCreate中来检查当前的方向,然后可以让你的setContentView来载入不同的layout xml。
@Overrideprotected void onCreate(Bundle icicle) { super.onCreate(icicle); int mCurrentOrientation= getResources().getConfiguration().orientation; if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ){ // If current screen is portrait Log.i("info", "portrait"); // 竖屏 setContentView(R.layout.mainP); } else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) { //If current screen is landscape Log.i("info", "landscape"); // 横屏 setContentView(R.layout.mainL); } init();//初始化,赋值等操作 findViews();//获得控件 setListensers();//设置控件的各种监听方法}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
上面只是对布局切换做了描述,实际上由于重启Activity在未加处理的情况下必然导致数据的丢失和重新获取,这样用户体验会非常差。为此就要在切换前对数据进行保存,切换重启后对数据进行恢复,具体操作的步骤如下:
重写Activity.onRetainNonConfigurationInstance(),用户横竖屏切换前保存数据
@Override public Object onRetainNonConfigurationInstance() { final MyDataObject data = collectMyLoadedData(); return data; }
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
在onCreate()函数中调用getLastNonConfigurationInstance(),获取onRetainNonConfigurationInstance()保存的数据
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance(); if (data == null) { data = loadMyData(); } ... }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.非重启Activity的横竖屏切换的处理
虽然重启Activity为我们提供了保存数据和读取数据的方式,但是如此一来程序会显得有些繁琐,所以有时候程序员往往就不想让Activity重启,Android也为我们提供了解决方案,就是通过onConfigurationChanged拦截横竖屏变换,从而进行必要的重新布局和切换操作。操作步骤如下:
首先,manifest中为相应的Activity设置android:configChanges属性,从而让Activity不延续上述的重建流程,具体如下:
Andorid 3.2以前的SDK可以使用如下配置
android:configChanges=”orientation|keyboardHidden”
而Adnroid 3.2以后的SDK必须添加一个screenSize属性,具体如下
android:configChanges=”keyboardHidden|orientation|screenSize”
或者
android:configChanges=”orientation|screenSize”
关于configChanges的详细描述,后面有个简单补充章节,这里不做过多展开。
其次,在Activity或View的onConfigurationChanged(Configuration newConfig)函数中获取当前横竖屏参数。至于其调用顺序跟touch事件的传递顺序相似,不过他没有消费事件的概念,会顺次调用到每一个onConfigurationChanged函数。下面是重写Activity的例子:
//布局分别在layout-land和layout-port目录中的同名main.xml时
@Overridepublic void onConfigurationChanged (Configuration newConfig){ super.onConfigurationChanged(newConfig); setContentView(R.layout.main); //注意,这里删除了init(),否则又初始化了,状态就丢失 findViews(); setListensers();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
//布局为不按照layout-land和layout-port目录,而自定义名字时
@Overridepublic void onConfigurationChanged (Configuration newConfig){ super.onConfigurationChanged(newConfig); int mCurrentOrientation = getResources().getConfiguration().orientation; if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ) { // If current screen is portrait setContentView(R.layout.mainP); //注意,这里删除了init(),否则又初始化了,状态就丢失 findViews(); setListensers(); } else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) { //If current screen is landscape setContentView(R.layout.mainL); //注意,这里删除了init(),否则又初始化了,状态就丢失 findViews(); setListensers(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
当然有时候连布局都不用更改的话,就可以直接对原有控件进行调用操作了,比如:
public class MainActivity extends Activity { private TextView textView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.i("--Main--", "onCreate"); textView=(TextView)findViewById(R.id.tv_id); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Log.i("--Main--", "onConfigurationChanged"); if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){ textView.setText("当前屏幕为横屏"); }else{ textView.setText("当前屏幕为竖屏"); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
需要注意的是,onConfigurationChanged函数中只能获得横竖屏切换后的参数,在该函数中获取不到新的Layout和控件的尺寸位置信息,如果要处理尺寸和位置信息,必须通过消息异步或者延时调用,下面是一个App在横竖屏切换时需要重新设置popupWindow位置的代码:
@Overrideprotected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //View中不用创建Handler,可直接调用post操作 //new Handler().postDelayed(new Runnable() { // @Override // public void run() { // updatePopup(); // } //}, 500); postDelayed(new Runnable() { @Override public void run() { updatePopup(); // } }, 500);//如果不在post中,而是直接调用,那么弹出位置就会有问题}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
虽然上面没有看到对布局的显式调用进行重新布局,照理控件的对象没有被销毁,但是控件在横竖屏切换时应该是需要进行重新layout和measure,然后再进行重绘的,否则不会引发弹出框位置的变化,至于如何调用重新layout、measure和Draw操作,在这里就不多展开了。
3.结尾
虽然不是原创,但这是一个很好的开始,不是吗?
咳咳,本文大面积参考(抄袭)Android横竖屏切换小结
- 顶
- 1
- 踩
- 0
- 上一篇Android事件分发与处理简单整理
- 下一篇Activity的四种启动模式launchMode
我的同类文章
- •Activity的四种启动模式launchMode2016-11-16
- •Android事件分发与处理简单整理2016-09-24
- Android横竖屏切换引起问题的小结
- Android横竖屏切换引起问题的小结
- Android 横竖屏切换 引起的1s左右黑屏
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Android横竖屏切换小结
- Java运行时动态加载类之URLClassLoader
- 大三下学期一点想法
- pro*c宿主变量和指示变量
- Codeforces Round #402 (Div. 2) D(简单)(二分)
- 爱思华宝收购 Synchronoss 技术公司旗下 Mirapoint 软件业务
- Android横竖屏切换引起问题的小结
- Java多态性理解
- python精简总结
- Linux任务管理
- 渐进插值的LOOP 曲面细分
- Centos6下nmon 脚本监控服务器系统性能
- IT名企常见面试题总结之Java篇(一)
- Caffe 学习笔记(视觉层(Vision Layers)及参数)
- 什么是 TensorFlow?