android 手机屏幕旋转机制与使用说明
来源:互联网 发布:淘宝联盟社区 编辑:程序博客网 时间:2024/04/28 03:00
android 屏幕旋转机制与使用说明
一 Overview
在开发android应用的时候,有可能需要让应用程序随着系统设置而进行调整,比如判断系统的屏幕方向、判断系统方向的方向导航设备等。除此之外,还需要让应用程序监听系统设置的更改,对系统设置的更改作出响应。
如果系统需要监听系统设置的更改,则可以考虑重写Activity的onConfigurationChanged()方法,该方法是一个基于回调的事件处理方法;当系统的设置发生更改时,该方法会被自动触发。查阅AndroidAPI可以得知配置信息android:ConfigChanged实际对应的是Activity里的onConfigurationChanged()方法。
在一些特殊的情况中,你可能希望当一种或者多种配置改变时避免重新启动你的activity。你可以通过在manifest中设置android:configChanges属性来实现这点。你可以在这里声明activity可以处理的任何配置改变,当这些配置改变时不会重新启动activity,而会调它的onConfigurationChanged()方法。如果改变的配置中包含了你所无法处理的配置(在android:configChanges并未声明),你的activity仍然要被重新启动,onConfigurationChanged()将不会被调用。
android:configChanges=""中可以用的值,请查询具体的androidAPI。
本文主要是站在App的角度,分析屏幕旋转处理的一般使用方法和注意事项。然后简要介绍framework中的实现细节。
二 屏幕旋转状态监测
屏幕旋转处理的关键为获取屏幕旋转的信息,因此系统中就需要有一种机制,可以实时监测当前系统的屏幕角度。所以,首先,我们就关注一下Framework是如何实现实时监控系统中的oritentation状态的。
1.Orientation状态初始化与设置
setting设置
在Android的Settings->Display中有Orientation这一设置项。当选中时,屏幕会随设备旋转。
settings设置是在文件DisplaySettings.java中,该项对应的键字符串为:
private static final String KEY_ACCELEROMETER = "accelerometer";
其默认值保存在xml文件中,默认是Enable。UI程序初始化时会根据其值是否在复选框中打勾(代码在onCreate函数中):
public void onCreate(Bundle savedInstanceState){ Accelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER); mAccelerometer.setPersistent(false);}
保存setting更改
当用户改变了Android的Settings-> Display中有Orientation这一设置项时,会保存起来:public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference == mAccelerometer) { RotationPolicy.setRotationLockForAccessibility( getActivity(), !mAccelerometer.isChecked()); } else if (preference == mNotificationPulse) { boolean value = mNotificationPulse.isChecked(); Settings.System.putInt(getContentResolver(), Settings.System.NOTIFICATION_LIGHT_PULSE, value ? 1 : 0); return true;}
监听setting的变化
在文件frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中的mSettingsObserver会随时监控其值,对用户设置做出应:
mSettingsObserver的初始化代码如下:
mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe();
一旦mSettingsObserver监听到Android的Settings-> Display中有Orientation这一设置项有变化,会马上回调它的onChange( )方法。
onChange( )实现代码如下:@Override public void onChange(boolean selfChange) { updateSettings(); updateRotation(false); }
2 监听oritentation状态
初始化
同2.1.3节所述,也是在文件PhoneWindowManager.java中实现实时监控oritentation的状态的。是通过变量mOrientationListener监听oritentation状态的。
初始化代码如下:
mOrientationListener = new MyOrientationListener(mContext, mHandler); try { mOrientationListener.setCurrentRotation(windowManager.getRotation()); } catch (RemoteException ex) { }
实时监测
一旦oritentation状态发生变化,mOrientationListener的onProposedRotationChanged会被调用。其code如下:
class MyOrientationListener extends WindowOrientationListener{ MyOrientationListener(Context context, Handler handler){ super(context, handler); }
@Override public voidonProposedRotationChanged(int rotation) { if (localLOGV) Slog.v(TAG, "onProposedRotationChanged,rotation=" + rotation); updateRotation(false); } }
我们不难发现,onProposedRotationChanged()函数中会调用updateRotation(false),实现对屏幕旋转的处理。
以上就是android实现的如何实时监测oritentation的状态。至于针对该状态,framework做什么样的处理,后续通过继续分析updateRotation(false)来说明。
三 屏幕旋转处理
默认情况
如果没有针对性地做任何处理的话,默认情况下,当用户手机的重力感应器打开后,旋转屏幕方向,会导致app的当前activity发生onDestroy->onCreate,会重新构造当前activity和界面布局。其实现机制为:当Configuration改变后,ActivityManagerService将会发送"配置改变"的广播,会要求ActivityThread重新启动当前focus的Activity,这是默认情况。
如果想很好地支持屏幕旋转,则建议在res中建立layout-land和layout-port两个文件夹,把横屏和竖屏的布局文件放入对应的layout文件夹中。
如果不申明android:configChanges="",按照Activity的生命周期,都会去执行一次onCreate()方法,而onCreate()方法通常会在显示之前做一些初始化工作。这样就有可能造成重复的初始化,必然降低程序效率,而且更有可能因为重复的初始化而导致数据的丢失。
设置固定的屏幕方向
android:screenOrientation属性的意义为,固定屏幕显示方向
主要的几个属性如下表:
"unspecified"
默认值,由系统来选择方向。它的使用策略,以及由于选择时特定的上下文环境,可能会因为设备的差异而不同。
"user"
使用用户当前首选的方向。
"behind"
使用Activity堆栈中与该Activity之下的那个Activity的相同的方向。
"landscape"
横向显示(宽度比高度要大)
"portrait"
纵向显示(高度比宽度要大)
"reverseLandscape"
与正常的横向方向相反显示,在APILevel 9中被引入
"reversePortrait"
与正常的纵向方向相反显示,在APILevel 9中被引入
"sensor"
显示的方向是由设备的方向传感器来决定的。显示方向依赖与用户怎样持有设备;当用户旋转设备时,显示的方向会改变。但是,默认情况下,有些设备不会在所有的四个方向上都旋转,因此要允许在所有的四个方向上都能旋转,就要使用fullSensor属性值。
"nosensor"
屏幕的显示方向不会参照物理方向传感器。传感器会被忽略,所以显示不会因用户移动设备而旋转。除了这个差别之外,系统会使用与“unspecified”设置相同的策略来旋转屏幕的方向。
如上表所示,在AndroidManifest.xml对应的activity属性中,添加:
android:screenOrientation="landscape" //横屏 或者 android:screenOrientation="portrait" //竖屏
那么,应用启动后,会固定为指定的屏幕方向,即使屏幕旋转,Activity也不会出现销毁或者转向等任何反应。这是由于PhoneWindowManager通知WindowManagerService更新Orientation的时候,WindowManagerService在函数updateRotationUnchecked()中会通过判断当前的orientation是否有变化:
public void updateRotationUnchecked(t) { boolean changed; synchronized(mWindowMap) { changed = updateRotationUncheckedLocked(false); if (!changed || forceRelayout) { getDefaultDisplayContentLocked().layoutNeeded =true; performLayoutAndPlaceSurfacesLocked(); } } if (changed ||alwaysSendConfiguration) { sendNewConfiguration(); } }
由于android:screenOrientation将屏幕设定为固定值,因此函数updateRotationUncheckedLocked永远返回false,此时只是重新布局activity并绘制,而没有通知AMSconfiguration的变化。因此即使屏幕旋转,Activity也不会出现销毁或者转向等任何反应。
强制开启屏幕旋转
如果用户的手机没有开启重力感应器或者在AndroidManifest.xml中设置了android:screenOrientation,默认情况下,该Activity不会响应屏幕旋转事件。如果在这种情况下,依然希望Activity能响应屏幕旋转,则添加如下代码:
// activity的onCreate函数中
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
此时,尽管没有在manifest中设置android:configChanges,系统仍能够捕获屏幕旋转事件,这是由于函数setRequestedOrientation本质上是重新设置了当前window关于Orientation的配置属性,并更新oritentation状态。setRequestedOrientation核心代码(ActivityManagerService.java)如下:
setRequestedOrientation( ){……//更新Orientation的属性配置mWindowManager.setAppOrientation(r.appToken, requestedOrientation);//更新当前系统的oritentation状态Configurationconfig =mWindowManager.updateOrientationFromAppTokens( mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);……}
捕获屏幕旋转事件,并且不希望activity被销毁
当设置android:configChanges="orientation|screenSize"之后,屏幕方向发生改变时,就可以触发onConfigurationChanged事件。其基本的实现原理为:当Configuration改变后,ActivityManagerService会发送"配置改变"的广播,会要求ActivityThread重新启动当前focus的Activity。这是我们前面描述的默认情况。
如果我们配置Activity的android:configChanges信息,那么就可以避免对Activity销毁再重新创建,而是调用activity的onConfigurationChanged方法。由于这部分代码量很大,此处仅仅列出framework流程图:
由上面的流程图可以看出,如果希望捕获屏幕旋转事件,并且不希望activity 被销毁,应该采用如下的方法:(1)在AndroidManifest.xml对应的activity属性中,添加:android:configChanges="orientation|screenSize"
此时如果屏幕旋转,就会触发orientation状态监听器mOrientationListener的函数onProposedRotationChanged,最终导致调用Activity的onConfigurationChanged方法。
注意:如果你的开发API等级等于或高于13,你还需要设置screenSize,因为screenSize会在屏幕旋转时改变。这与android代码升级有关系,记住即可。(2)在对应的activity中,重载函数onConfigurationChanged()即可。
@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged (newConfig);//……}
五 结束语
至此,我们就分析完了屏幕旋转相关知识,包括旋转信息的捕获以及后续的处理。屏幕旋转是一个android应用开发中,经常遇到的一个问题。看似简单,但是有几点需要注意:
1.注意区分configChanges和screenOrientation的不同,很多同事可能之前没有关注过。
2.配置android:configChanges时,需要设置screenSize,因为screenSize会在屏幕旋转时改变。否则onConfigurationChanged不会被调用。
- android 手机屏幕旋转机制与使用说明
- android获取手机屏幕尺寸和旋转方向
- 手机屏幕旋转180度
- 检测手机屏幕的旋转
- 判断手机屏幕旋转方向
- IOS - 判断手机屏幕旋转
- 判断手机屏幕是否旋转
- android 点亮手机屏幕与屏幕解锁方法
- Android图片与旋转
- Android图片与旋转
- Android中音频管理--AudioFocus机制使用说明
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Android 解决setRequestedOrientation之后手机屏幕的旋转不触发onConfigurationChanged方法
- Andrew Ng机器学习笔记(四)——GLM广义线性模型
- HTTP状态码->HTTP Status Code
- freeSwitch中eventList关于event socket的
- Windows2000_下_APACHE+OpenSSL+MOD_SSL_的安装
- requirejs 配置问题
- android 手机屏幕旋转机制与使用说明
- 2014年阅读清单
- 20150107 N2
- emc 中英文
- ubuntu使用ssh连接远程电脑的方法
- python select
- jsp引入另一个页面
- 编程必知的10个Unix命令技巧
- 在ListView的getView里根据条件设置背景色后,背景会错乱