在不重新启动当前 activity 的情况下在方向更改时调用 activity

Invoke activity on orientation change without restarting current activity

我有一个包含许多活动的应用程序,它的布局适合 phone 大小的 (SFF) 和平板电脑大小的 (LFF) 设备。对于 LFF 设备,框架在方向更改(横向 <-> 纵向)时自动重新创建活动,效果很好,可以满足我的要求。在 SFF 设备上操作时,我可以使用 Activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT).

将方向锁定为纵向

当 运行 在 SFF 设备上时,我想在设备物理旋转到横向时启动不同的 activity。 (让我们暂且不讨论在旋转时启动不同的 activity 是否是一个好的设计原则。)

最初我在横向时使用 OrientationEventListener to monitor the rotation but this fails in the case of an SFF device whose "natural" orientation is landscape. OrientationEventListener.onOrientationChanged() will report 0 degrees (+/-45) and WindowManager.getDefaultDisplay().getRotation() will report Surface.ROTATION_0。我无法找到一种方法来确定设备的 "natural" 方向以补偿报告的旋转值。有几个 SO 问题讨论了这个问题,但 none 似乎有一个令人满意的答案。

另一种选择是使用 android:configChanges="orientation|screenSize" in the manifest and catch the orientation change in onConfigurationChanged()。这样做的问题是它破坏了 LFF 设备的默认行为,而我希望保留这种行为。一个可怕的 hack 确实出现了:用 LFF 和 SFF 版本复制清单中的每个 activity,一个有 android:configChanges 集,一个没有 android:configChanges 集,然后让 activity 每个选择合适的版本是时候启动新的 activity.

我当前的解决方案既不使用 android:configChanges 也不使用 setRequestedOrientation()OrientationEventListener。相反,我有一个布尔资源 is_landscape,定义在 values-land 中,我在相关活动的 onCreate() 中对此进行了测试。这有缺点,在旋转到景观时:

谁能提出更好的解决方案,包括可能发现设备 "natural" 方向的方法?我需要这个才能回到 Android 4.0.

您必须使用 getRotationgetResources().getConfiguration() 的组合来检查自然方向。

public int getDefaultOrientation() {
    WindowManager windowManager =  (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    Configuration config = getResources().getConfiguration();
    int rotation = windowManager.getDefaultDisplay().getRotation();

    if ( ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
            config.orientation == Configuration.ORIENTATION_LANDSCAPE)
        || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&    
            config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
      return Configuration.ORIENTATION_LANDSCAPE;
    } else { 
      return Configuration.ORIENTATION_PORTRAIT;
    }
}