Activity 在 Android 8.1 版本设备上完成时如何防止屏幕方向发生变化?

How to prevent Screen Orientation change when Activity finishes on Android 8.1 Version Devices?

我正在开发一个应用程序,在 8.1 设备(Pixel2、Nexus5x)上遇到了一个奇怪的行为,所以我写了一个小应用程序来验证这个行为。

MainActivity 锁定为 portrait 模式,而 LandscapeActivity 锁定为 landscapeMainActivity 为结果启动 LandscapeActivity。屏幕按预期从 portrait 切换到 landscapeLandscapeActivity 完成后,它将结果传播到 MainActivity,同时切换回 portrait(如预期)。

但有时我会在这里遇到某种错误。在 MainActivity 中的 onActivityResult 之后,它从 portrait 切换到 landscape 并立即切换回 portrait。虽然我可以处理状态,但它看起来仍然令人讨厌。

为了可追溯性,我将 post 重建它的所有内容。

我能做些什么来防止它?另请注意,它不会每次都发生,据我所知,我只能在 8.1 设备上进行测试。在 8.1

以下的 android 设备上似乎没问题

编辑: 正如@Floern 在他的回答中建议的那样,将 android:configChanges="orientation|screenSize" 添加到我的清单中,但没有成功。 确认平台错误也是可以接受的答案

清单

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".LandscapeActivity"
            android:screenOrientation="landscape"/>

    </application>

主要活动

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();

    private static final int REQ_CODE = 878;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: savedInstanceState=" + savedInstanceState + ", orientation=" + orientation());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, LandscapeActivity.class);
                startActivityForResult(intent, REQ_CODE);

            }
        });
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: orientation=" + orientation());
        super.onResume();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause: orientation=" + orientation());
        super.onPause();
    }

    @Override
    protected void onStart() {
        Log.d(TAG, "onStart: orientation=" + orientation());
        super.onStart();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "onStop: orientation=" + orientation());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy: orientation=" + orientation());
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult: orientation=" + orientation());
        if (requestCode == REQ_CODE){
            Toast.makeText(this, "Result=" + data.getStringExtra(LandscapeActivity.KEY_DATA), Toast.LENGTH_LONG).show();
        }
    }

    String orientation(){
        return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ?  "Landscape" : "Portrait";
    }
}

景观活动

public class LandscapeActivity extends AppCompatActivity{

    public static final String TAG = LandscapeActivity.class.getSimpleName();

    public static final String KEY_DATA = "DATA";
    static int COUNTER = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: savedInstanceState=" + savedInstanceState + "orientation=" + (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ?  "Landscape" : "Portrait"));
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent data = new Intent();
                COUNTER++;
                data.putExtra(KEY_DATA, "Runned " + COUNTER + " times");
                setResult(RESULT_OK, data);
                finish();
            }
        });
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: orientation=" + orientation());
        super.onResume();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause: orientation=" + orientation());
        super.onPause();
    }

    @Override
    protected void onStart() {
        Log.d(TAG, "onStart: orientation=" + orientation());
        super.onStart();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "onStop: orientation=" + orientation());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy: orientation=" + orientation());
        super.onDestroy();
    }

    String orientation(){
        return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ?  "Landscape" : "Portrait";
    }
}

build.gradle

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "android.example.com.orientationtest8_1"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

布局activity_main文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="android.dermalog.com.orientationtest8_1.MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

最后一个通过重复点击按钮的日志:

01-04 15:18:06.744  D/MainActivity: onCreate: savedInstanceState=null
01-04 15:18:06.847  D/MainActivity: onStart: orientation=Portrait
01-04 15:18:06.850  D/MainActivity: onResume: orientation=Portrait
01-04 15:18:14.036  D/MainActivity: onPause: orientation=Portrait
01-04 15:18:14.108  D/LandscapeActivity: onCreate: savedInstanceState=nullorientation=Landscape
01-04 15:18:14.139  D/LandscapeActivity: onStart: orientation=Landscape
01-04 15:18:14.141  D/LandscapeActivity: onResume: orientation=Landscape
01-04 15:18:14.217  D/MainActivity: onStop: orientation=Portrait
01-04 15:18:15.643  D/LandscapeActivity: onPause: orientation=Landscape
01-04 15:18:15.711  D/MainActivity: onActivityResult: orientation=Portrait
01-04 15:18:15.719  D/MainActivity: onStart: orientation=Portrait
01-04 15:18:15.720  D/MainActivity: onResume: orientation=Portrait
01-04 15:18:15.786  D/LandscapeActivity: onStop: orientation=Landscape
01-04 15:18:15.786  D/LandscapeActivity: onDestroy: orientation=Landscape
01-04 15:18:18.036  D/MainActivity: onPause: orientation=Portrait
01-04 15:18:18.097  D/LandscapeActivity: onCreate: savedInstanceState=nullorientation=Landscape
01-04 15:18:18.121  D/LandscapeActivity: onStart: orientation=Landscape
01-04 15:18:18.123  D/LandscapeActivity: onResume: orientation=Landscape
01-04 15:18:18.213  D/MainActivity: onStop: orientation=Portrait
01-04 15:18:19.505  D/LandscapeActivity: onPause: orientation=Landscape
01-04 15:18:19.564  D/MainActivity: onActivityResult: orientation=Portrait
01-04 15:18:19.569  D/MainActivity: onStart: orientation=Portrait
01-04 15:18:19.569  D/MainActivity: onResume: orientation=Portrait
01-04 15:18:19.639  D/LandscapeActivity: onStop: orientation=Landscape
01-04 15:18:19.640  D/LandscapeActivity: onDestroy: orientation=Landscape
01-04 15:18:20.102  D/MainActivity: onPause: orientation=Portrait
01-04 15:18:20.103  D/MainActivity: onStop: orientation=Portrait
01-04 15:18:20.104  D/MainActivity: onDestroy: orientation=Portrait
01-04 15:18:20.123  D/MainActivity: onCreate: savedInstanceState=Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState@7ceec3, 2131165191=android.support.v7.widget.Toolbar$SavedState@3c34340, 2131165193=android.view.AbsSavedState@7ceec3, 2131165199=android.view.AbsSavedState@7ceec3, 2131165219=android.view.AbsSavedState@7ceec3, 2131165229=android.view.AbsSavedState@7ceec3}}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@c215279}]
01-04 15:18:20.149  D/MainActivity: onStart: orientation=Landscape
01-04 15:18:20.152  D/MainActivity: onResume: orientation=Landscape
01-04 15:18:20.699  D/MainActivity: onPause: orientation=Landscape
01-04 15:18:20.701  D/MainActivity: onStop: orientation=Landscape
01-04 15:18:20.702  D/MainActivity: onDestroy: orientation=Landscape
01-04 15:18:20.718  D/MainActivity: onCreate: savedInstanceState=Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState@7ceec3, 2131165191=android.support.v7.widget.Toolbar$SavedState@807af46, 2131165193=android.view.AbsSavedState@7ceec3, 2131165199=android.view.AbsSavedState@7ceec3, 2131165219=android.view.AbsSavedState@7ceec3, 2131165229=android.view.AbsSavedState@7ceec3}}], android:lastAutofillId=1073741823, android:fragments=android.app.FragmentManagerState@8d12507}]
01-04 15:18:20.748  D/MainActivity: onStart: orientation=Portrait
01-04 15:18:20.751  D/MainActivity: onResume: orientation=Portrait

这可能确实是一个框架错误。我在仅纵向应用程序中横向使用相机应用程序(通过 Intent)时注意到三星设备上的类似行为。我无法弄清楚到底是什么原因,但我找到了一个可以将影响降到最低的解决方法。

如果您通过将 android:configChanges="orientation|screenSize" 添加到您的 Activity 告诉系统您想要自己处理方向更改,它不会在方向更改时重新创建。因此,您可以避免重新创建 Activity(两次)的开销,这可能会将性能提高到您根本不会注意到方向变化的程度。

<activity android:name=".MainActivity"
    android:screenOrientation="portrait"
    android:configChanges="orientation|screenSize">

bug 已修复。所以等待下一个 release/patch.

是的,这是 Android 8.1 OS 版本中的一个问题。因为这已经过时了。我们可以解决这类问题。在这个特定的 API 级别中,Android OS 可能会存储最新的方向值,并且会应用于所有屏幕,直到前一个屏幕或该特定屏幕被销毁。因此,解决此类问题的方法是在返回屏幕之前更改方向。
例如:

如果 ScreenA 处于纵向模式,而 screenB 处于横向模式,并且如果屏幕移动到横向的 ScreenB,并且如果您在没有杀死 ScreenB(恢复 ScreenA)的情况下返回到 ScreenA,则 screenA 在横向中也可见。
要解决此问题,请在 ScreenB 的 onPause()OnStop() 中强制将 ScreenA 的方向更改为纵向(以恢复 ScreenA).

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

此调用后,ScreenA 将处于纵向。 此外,在 ScreenB 的 onResume() 中,

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