本文带你从framework的视角了解转屏从产生到结束这一过程,应用开发中转屏相关的知识点已经有很多现成的资料,不在这里的讨论范围。
转屏的流程非常简单,如下:
下面将分为三个阶段进行讨论,本文贴出的代码来源于Android N。
转屏的产生
框架利用一定的策略来确定当前的屏幕方向,依据主要是窗口的screenOrientation,以及其它的一些状态,比如系统是否开启了屏幕旋转、系统是否固定了屏幕方向、是否处于dock模式等。
在讲如何确定屏幕方向前,先介绍窗口的screenOrientation。对于一个窗口,根据是否Activity窗口,以不同的方式来声明screenOrientation:
- Activity窗口:
1、(静态)AndroidManifest.xml中配置screenOrientation
2、(动态)通过Activity.setRequestedOrientation()
/**
* Change the desired orientation of this activity. If the activity
* is currently in the foreground or otherwise impacting the screen
* orientation, the screen will immediately be changed (possibly causing
* the activity to be restarted). Otherwise, this will be used the next
* time the activity is visible.
*
* @param requestedOrientation An orientation constant as used in
* {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
*/
public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
if (mParent == null) {
try {
ActivityManagerNative.getDefault().setRequestedOrientation(
mToken, requestedOrientation);
} catch (RemoteException e) {
// Empty
}
} else {
mParent.setRequestedOrientation(requestedOrientation);
}
}
- 非Activity窗口:指定WindowManager.LayoutParams.screenOrientation
/**
* Specific orientation value for a window.
* May be any of the same values allowed
* for {@link android.content.pm.ActivityInfo#screenOrientation}.
* If not set, a default value of
* {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
* will be used.
*/
public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
窗口的screenOrientation默认为ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED(不指定方向),另外还有个特殊的值为ActivityInfo.SCREEN_ORIENTATION_BEHIND(由下方的窗口指定方向)。
现在可以开始讲屏幕方向的确定过程,主要是两个步骤:
从上到下遍历窗口堆栈,在可见的窗口中确定一个基准screenOrientation
1)非Activity窗口的screenOrientation如果不是上述的两个值,则结束遍历
2)一旦遍历到一个Activity窗口,接下来仅在Activity窗口中遍历,不再关心非Activity窗口根据第一步算出的基准screenOrientation,按照一定策略计算出最终屏幕方向,有兴趣的可以参考源码
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
public int rotationForOrientationLw(int orientation, int lastRotation);
根据第一点可以知道,一个比较高层级的非Activity窗口,是可以通过配置screenOrientation来让自己成为基准screenOrientation的确定者,进而影响最终的屏幕方向。
那么转屏的原因很简单,即系统在某一时刻计算出的屏幕方向发生了变化,常