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);}
      @Overridepublic 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()即可。
@Override
public void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged (newConfig);
//……
}

五 结束语

至此,我们就分析完了屏幕旋转相关知识,包括旋转信息的捕获以及后续的处理。屏幕旋转是一个android应用开发中,经常遇到的一个问题。看似简单,但是有几点需要注意:

1.注意区分configChanges和screenOrientation的不同,很多同事可能之前没有关注过。

2.配置android:configChanges时,需要设置screenSize,因为screenSize会在屏幕旋转时改变。否则onConfigurationChanged不会被调用。

android 手机屏幕旋转机制与使用说明相关推荐

  1. 【Android RTMP】NV21 图像旋转处理 ( 问题描述 | 图像顺时针旋转 90 度方案 | YUV 图像旋转细节 | 手机屏幕旋转方向 )

    文章目录 安卓直播推流专栏博客总结 一. NV21 图像格式与 Camera图像传感器方向问题 二. NV21 图像格式视频旋转 1. 图像旋转问题及解决方案 ( 顺时针旋转 90 度 ) 2. NV ...

  2. Android实现屏幕旋转方法

    本文实例总结了Android实现屏幕旋转方法.分享给大家供大家参考.具体如下: 在介绍之前,我们需要先了解默认情况下android屏幕旋转的机制: 默认情况下,当用户手机的重力感应器打开后,旋转屏幕方 ...

  3. Android 禁止屏幕旋转 旋转屏幕时保持Activity内容

    Android 禁止屏幕旋转 & 旋转屏幕时保持Activity内容 1.在应用中固定屏幕方向. 在AndroidManifest.xml的activity中加入:            an ...

  4. android 屏幕旋转流程,android自动屏幕旋转流程分析.doc

    android自动屏幕旋转流程分析.doc android自动屏幕旋转流程分析 在android设置(Settings)中我们可以看到显示(display)下有一个自动屏幕旋转的checkbox, 如 ...

  5. android分辨率选择,安卓Android手机屏幕壁纸分辨率选择技巧

    大家先看看对应的壁纸分辨率: 屏幕分辨率为 480×320 的Android手机,对应的壁纸分辨率为:640x480. 屏幕分辨率为 800×480 的Android手机,对应的壁纸分辨率为:960x ...

  6. android壁纸和手机屏幕之间要怎么对应,安卓Android手机屏幕壁纸分辨率选择技巧...

    安卓Android手机屏幕壁纸分辨率选择技巧 现在使用安卓手机的人好多了,一个好的手机壁纸自然是大家的追求,那么要怎么挑选适合自己安卓手机的手机壁纸呢~登博教程小编来教你挑选吧~ 大家先看看对应的壁纸 ...

  7. android手机屏幕总是闪烁,手机屏幕闪烁是什么原因

    手机屏幕闪烁会严重影响到我们对手机的使用,那么在遇到这种情况的时候我们应该怎么解决呢?下面是小编精心为你整理的手机屏幕闪烁的原因,一起来看看. 手机屏幕闪烁的原因 其实很多时候是由于静电造成的,我们可 ...

  8. Android手机模拟器旋转快捷键

    Android手机模拟器旋转快捷键:CTRL+F11 转载于:https://blog.51cto.com/568464209/1308983

  9. 修复Android手机屏幕的5种简单方法是黑色的

    作为Android用户,您是否遇到过以下情况: Android 设备的通知指示灯持续闪烁,但设备没有响应. 手机屏幕经常冻结. Android手机经常重新启动或崩溃. 安卓手机电池消耗得非常快. 您的 ...

最新文章

  1. 由于这个现象,我们永远无法精确测量时间
  2. First use cursor and initially understand it
  3. 2013年3月空调类品牌网络知名度排名
  4. 电脑显示器不亮主机正常_为什么会突然显示器黑屏但主机正常工作和解决办法。...
  5. 【Android基础】短信的发送
  6. 学习ActiveMQ(五):activemq的五种消息类型和三种监听器类型
  7. 如何在后台配置中找到某个具体配置的事务码
  8. 一文详解深度相机之TOF成像
  9. Matlab程序如何打包
  10. Schedule定时器cron表达式
  11. 基于SSM框架的生源地助学贷款管理系统的设计与实现
  12. java big5转换为gbk_简体繁体转换代码(Big5-GB | GBK简体-GBK繁体)
  13. 【计算机网络】谢希仁笔记 数据链路层
  14. DNS域名解析服务介绍
  15. Linux文件与目录的三种时间状态(mtime,atime,ctime)区别
  16. 网易蜂巢(云计算基础服务)MongoDB服务重磅来袭
  17. 老佛爷“驾到”潮爆的IT Bag也来了(组图)
  18. 掘安平台Writeup(持续解题)
  19. 客服对于Kindle电子书的退货、倒闭、VR等问题的回答
  20. html界面等待状态,html页面Loading效果实现:加载新页面前的等待过渡画面

热门文章

  1. 大工《模拟电子线路实验》大作业离线作业
  2. National Day meets Mid-autumn Festival
  3. java鼠标指针锤子,java线程工具走出锤子敲铁皮时代。
  4. dovecot MySQL配置_dovecot+mysql配置及搭建邮件云服务器方法
  5. 徐州有华为,转型“真办肆”
  6. Redisson分布式锁及springboot 整合实例
  7. python程序下载大量天文学数据
  8. 位图(.bmp)文件结构
  9. Android 自定义相机(可外接摄像头)
  10. 计网IP地址,网络号,子网号,主机号,示例题解,读这一篇就够了!!!