Android 8.1 屏幕方向问题:将竖屏屏幕翻转为横屏时出现的问题

57

除了播放视频的活动外,我所有的活动都是纵向模式。我发现在Android 8.1上,每次打开视频活动并关闭它后,即使在清单上设置为“纵向”,以前的活动也会进入横向模式。

  1. 有时进入纵向模式,然后进入横向模式并保持在横向模式。
  2. 有时进入纵向模式,然后进入横向模式,最后再次进入纵向模式。

只有当从横向活动返回时才会发生这种情况。

是否有其他人遇到过这个问题?

谢谢。

编辑

我在Google上报告了此错误:https://issuetracker.google.com/issues/69168442

编辑2

在Android 9上似乎已经解决了这个问题。


2
还是没有新的进展吗?我也遇到了这个bug,但在我使用的应用中,这种情况只会发生在完全以竖屏模式运行并且只有当使用startActivityForResult()调用的活动返回结果后(因此我们回到调用者活动)时。 - lcw_gg
你解决了这个问题吗?我也遇到了同样的问题。 - Wun
没有,目前还没有解决方案。看起来我报告的错误被其他我们无法访问的问题所阻塞了。https://issuetracker.google.com/issues/69168442 - Sol
我遇到了与我的设备有关的问题,但行为略有不同。目前还没有可行的解决方案。https://stackoverflow.com/questions/49232198/screen-rotate-3-times-when-back-to-landscape-activity-from-portrait-activity - quangkid
面对相同的奇怪问题。 - Smeet
显示剩余3条评论
10个回答

16

我在我的应用程序中遇到了这个问题。

对我有效的解决方案如下:

onCreate(){
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}

onPause(){ 
  if (android.os.Build.VERSION.SDK_INT >= 27) {
         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
  }
}

onResume(){
  if (android.os.Build.VERSION.SDK_INT >= 27) {
         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
  }
}

以上代码应该放在处于横屏模式的活动中(即第二个活动,并且您从其中按下返回按钮的活动)。

我想指出,这个解决方案不是我自己的,而是来自以下链接的#20帖子(也在OP中注明):

https://issuetracker.google.com/issues/69168442

我只是觉得如果人们不必搜索另一页就可以轻松访问它,那可能会更容易些。


谢谢,但请解释一下 - 何时使用setRequestedOrientation(...)方法 - 在super.onPause()之前还是之后? onResume()也是同样的情况。 - Taras Vovkovych
在这种情况下,没有任何区别(我只是测试了一下以确保)。我个人在super之后调用了方法,因为这对我来说是最合适的。如果super调用中有任何导致故障的内容,则需要在super之后应用代码。 - thetestspecimen
在之前的Activity中使用intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)解决了我的问题。 - Luvnish Monga
@LuvnishMonga 我也尝试了同样的方法,但我仍然遇到了方向问题。我已经使用了那些标志来启动我的活动。如果您能发送任何代码片段,我将不胜感激。 - VV W
如果我在onCreate中放置setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);这行代码,我会得到异常Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation。 - VV W

10

这解决了问题。

覆盖 Landscape activityonBackPressed() 方法,并将方向设置为 Portrait

@Override
public void onBackPressed() {
    super.onBackPressed();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

3
如果您在清单文件中使用了像theme=Theme.AppCompat.Light.Dialog这样的DialogTheme,请从清单文件中删除该Dialog活动的set orientation标记,它将从上一个活动中获取方向,并为剩余的活动放置set orientation标记。
对于以下版本,请将此代码放置在oncreate中。
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  }

并为应用程序设置主题Theme.AppCompat.Light.DarkActionBar,无需将主题添加到活动中


1
在前一个Activity中使用intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)解决了我的问题。

是的,我在Oreo中遇到了这个问题,这是我为Oreo找到的解决方案。 - Luvnish Monga
************* 已解决 ************************************ 如果您将DialogTheme放置在活动中,请从活动标记中删除设置方向,它将从上一个活动中获取方向。 - VV W
@AhmadArslan 实际上,对于Android 8.0而言,前一个活动的方向决定了基于对话框主题的活动的当前活动方向。 - VV W
你的意思是说,我需要在清单文件中使用"parent="Theme.AppCompat..Dialog"主题,而不是使用"parent="Theme.AppCompat.Light",并且从清单文件中删除所有方向设置,改为在程序中编程设置方向吗? - Ahmad Arslan
@AhmadArslan 不需要,如果你在清单文件中有“parent=”Theme.AppCompat..Dialog”,那么只需从清单文件中删除Orientation标签,并为剩余的活动设置方向即可。将对话框放置在onCreate中,如果(android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O),则使用setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)。 - VV W
显示剩余3条评论

1
如果您需要在父活动中支持方向更改,请考虑在横屏活动的onPause()中使用当前方向。
onCreate(){
   super.onCreate();
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}

onPause(){ 
  super.onPause();
  if (android.os.Build.VERSION.SDK_INT >= 27) {
         setRequestedOrientation(getResources().getConfiguration().orientation);
  }
}

onResume(){
  super.onResume();
  if (android.os.Build.VERSION.SDK_INT >= 27) {
         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
  }
}

这个答案基于TheTestSpecimen的答案。

1

来自 Narmi 的回答:

当你从活动B返回到活动A时,如果你知道活动A的屏幕方向,则在活动B的ondestroy中设置屏幕方向。

你需要检测活动是否因配置更改而被销毁,所以添加字段 isConfigurationChanged = false,然后在 onSaveInstanceState 方法中将其设置为 true,并在 onDestroy 方法中添加以下代码:

@Override
protected void onDestroy() {
    if(!isConfigurationChanged)
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    super.onDestroy();
}

0
在每个活动的onCreate方法中插入这行代码。
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

针对景观和

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

针对纵向的那些


1
我已经将其放在清单上,并且适用于除8.1以外的所有Android版本。 - Sol
尝试在onResume中执行-您的活动可能没有被销毁,因此在该特定点上可能不会调用onCreate()。 - Will

0

我遇到了这样的问题,尝试了以上所有用例。 大多数情况下都有效,但有一个情况需要注意:

最终原因是在Android 8中,在活动内容布局中使用片段。 例如:活动在横屏模式下启动,但片段显示纵向布局。

尽量避免使用片段。


0

下一个解决方法可能会帮助您解决问题。

您必须使用代码中的所有活动来扩展它。每当调用 onPause / onResume 方法时,它会负责设置和恢复正确的方向。

此解决方法适用于在清单活动标签中定义的任何类型的方向。

出于我的目的,我将此类从ComponentActivity扩展,因此您可能需要更改此类以从您在代码中使用的ActivityActivityCompat或其他类型的活动扩展。

public abstract class AbsBaseActivity extends ComponentActivity
{
    private int currentActivityOrientation   = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    private int parentActivityOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

    @CallSuper
    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        this.cacheOrientations();
    }

    private void cacheOrientations()
    {
        if (this.currentActivityOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
        {
            final Intent parentIntent = this.getParentActivityIntent();

            if (parentIntent != null)
            {
                final ComponentName parentComponentName = parentIntent.getComponent();

                if (parentComponentName != null)
                {
                    this.currentActivityOrientation = this.getConfiguredOrientation(this.getComponentName());
                    this.parentActivityOrientation = this.getConfiguredOrientation(parentComponentName);
                }
            }
        }
    }

    private int getConfiguredOrientation(@NonNull final ComponentName source)
    {
        try
        {
            final PackageManager packageManager = this.getPackageManager();
            final ActivityInfo   activityInfo   = packageManager.getActivityInfo(source, 0);
            return activityInfo.screenOrientation;
        }
        catch (PackageManager.NameNotFoundException e)
        {
            e.printStackTrace();
        }

        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    }

    @CallSuper
    @Override
    protected void onPause()
    {
        if (this.parentActivityOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
        {
            this.setRequestedOrientation(this.parentActivityOrientation);
        }

        super.onPause();
    }

    @CallSuper
    @Override
    protected void onResume()
    {
        super.onResume();

        if (this.currentActivityOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
        {
            this.setRequestedOrientation(this.currentActivityOrientation);
        }
    }
}

0

и§ЈеҶіжӯӨй—®йўҳзҡ„ж–№жі•пјҡ

еҪ“жӮЁд»Һжҙ»еҠЁBиҝ”еӣһжҙ»еҠЁA并且зҹҘйҒ“жҙ»еҠЁAзҡ„еұҸ幕方еҗ‘ж—¶пјҢиҜ·еңЁжҙ»еҠЁBзҡ„ondestroyдёӯи®ҫзҪ®еұҸ幕方еҗ‘гҖӮ

@Override
protected void onDestroy() {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    super.onDestroy();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接