Android: временно отключить изменение ориентации в действии

В моей основной деятельности есть код, который вносит некоторые изменения в базу данных, которые нельзя прерывать. Я делаю тяжелую работу в другом потоке и использую диалоговое окно прогресса, которое я установил как неотменяемый. Однако я заметил, что если я поверну свой телефон, он перезапустит действие, что ДЕЙСТВИТЕЛЬНО плохо для запущенного процесса, и я получаю принудительное закрытие.

Что я хочу сделать, так это программно отключить изменение ориентации экрана, пока мой процесс не завершится, и тогда изменения ориентации будут включены.


person Christopher Perry    schedule 31.08.2010    source источник
comment
Поскольку никто не упоминает об этой части, вам нужно импортировать android.content.pm.ActivityInfo, чтобы использовать идентификатор ActivityInfo.   -  person zsalwasser    schedule 12.06.2011
comment
Посмотрите на stackoverflow.com/questions/6599770/screen-orientation-lock   -  person diyism    schedule 22.09.2011
comment
Обратитесь: stackoverflow.com/a/32885911/2673792 для лучшего решения   -  person Sudhir Sinha    schedule 03.05.2016


Ответы (17)


Как объяснил Крис в его самоответе, звоню

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

а потом

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

действительно работает как шарм ... на реальных устройствах!

Не думайте, что он сломан при тестировании на эмуляторе, сочетание клавиш ctrl + F11 ВСЕГДА меняет ориентацию экрана, без эмуляции движений датчиков.

РЕДАКТИРОВАТЬ: это был не лучший ответ. Как объясняется в комментариях, у этого метода есть проблемы. Настоящий ответ здесь < / а>.

person Kevin Gaudin    schedule 01.09.2010
comment
Я не мог найти эти константы. Спасибо за это. - person Christopher Perry; 02.09.2010
comment
Проблема с этими методами ... Похоже, если вы вызовете setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); когда устройство не используется в своей ориентации по умолчанию, тогда ориентация активности немедленно изменяется (уничтожается и воссоздается) на ориентацию устройства по умолчанию. Например, на телефоне, если вы держите его в альбомной ориентации, при повторной активации датчиков действие переключается на портретную и обратно на альбомную. Та же противоположная проблема с Archos A5 IT: использование его в портретной ориентации приводит к переключению активности в альбомную и обратно в портретную. - person Kevin Gaudin; 30.10.2010
comment
У меня это не сработало. Однако этот сработал: ​​stackoverflow.com/a/10488012/1369016 Мне пришлось вызвать setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); или setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); на основе текущей ориентации, полученной из getResources (). getConfiguration (). Ориентация. - person Bitcoin Cash - ADA enthusiast; 17.10.2014
comment
ActivityInfo.SCREEN_ORIENTATION_SENSOR не соблюдает встроенную блокировку ориентации Android. Сброс ориентации на ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED делает. - person tvkanters; 29.09.2016
comment
Зачем все усложнять? А как насчет простого добавления android: screenOrientation = portrait в манифест для определенного действия? см .: ​​stackoverflow.com/a/582585/4203016 - person nnyerges; 22.09.2019

Ни один из других ответов не помог мне идеально, но вот что я обнаружил.

Зафиксировать ориентацию на текущую ...

if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Когда изменение ориентации должно быть разрешено снова, установите значение по умолчанию ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
person Pilot_51    schedule 05.11.2010
comment
Проблема заключается в том, что Configuration.ORIENTATION_PORTRAIT будет возвращен в обоих ландшафтных режимах (т.е. «нормальный» и обратный). Поэтому, если телефон находится в перевернутой альбомной ориентации и вы установите ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, он перевернется вверх дном. В API 9 ActivityInfo вводит константу SCREEN_ORIENTATION_REVERSE_LANDSCAPE, но я не вижу способа определить такую ​​ориентацию через класс Configuration. - person Błażej Czapp; 20.04.2012
comment
Это сработало. Ответ на вышеуказанное беспокойство находится в этом ответе. stackoverflow.com/a/10453034/1223436 - person Zack; 31.12.2013
comment
Работал как шарм и для моих нужд, блестящее спасибо - person user2029541; 10.04.2016

Вот более полное и актуальное решение, которое работает для API 8+, работает для обратного портрета и ландшафта и работает на вкладке Galaxy, где «естественная» ориентация - альбомная (вызовите activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED), чтобы разблокировать ориентацию):

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public static void lockActivityOrientation(Activity activity) {
    Display display = activity.getWindowManager().getDefaultDisplay();
    int rotation = display.getRotation();
    int height;
    int width;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
        height = display.getHeight();
        width = display.getWidth();
    } else {
        Point size = new Point();
        display.getSize(size);
        height = size.y;
        width = size.x;
    }
    switch (rotation) {
    case Surface.ROTATION_90:
        if (width > height)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        break;
    case Surface.ROTATION_180:
        if (height > width)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        break;          
    case Surface.ROTATION_270:
        if (width > height)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        break;
    default :
        if (height > width)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}
person Roy    schedule 17.05.2013
comment
У меня отлично работал с планшетами и телефонами. - person ScruffyFox; 25.09.2014
comment
Единственно правильный ответ, который работает на всех устройствах для меня. - person amdev; 10.12.2014
comment
Однозначно лучший ответ! Вы можете сделать этот метод static и добавить Activity activity в качестве параметра. - person caw; 26.12.2014

Чтобы управлять режимами обратной ориентации, я использовал этот код для исправления ориентации активности:

int rotation = getWindowManager().getDefaultDisplay().getRotation();

    switch(rotation) {
    case Surface.ROTATION_180:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        break;
    case Surface.ROTATION_270:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);         
        break;
    case  Surface.ROTATION_0:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        break;
    case Surface.ROTATION_90:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        break;
    }

И снова разрешить ориентацию:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
person Ivan BASART    schedule 16.11.2013

Используйте setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); для блокировки текущей ориентации, будь то альбомная или книжная.

Используйте setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); для разблокировки ориентации.

person Sudhir Sinha    schedule 01.10.2015
comment
Лучшее решение для короткой временной блокировки. Никаких проблем с текущей ориентацией датчика. - person The incredible Jan; 08.05.2017
comment
работает над Build.VERSION.SDK_INT ›= 18, более полный ответ дает tdjprog на этой странице stackoverflow.com/a/41812971/5235263 - person bastami82; 29.07.2017

Я нашел ответ. Для этого в Activity вы можете вызвать setRequestedOrientation(int) с одним из указанных здесь значений: http://developer.android.com/reference/android/R.attr.html#screenOrientation

Перед тем, как начать обсуждение, я вызвал setRequestedOrientation(OFF) (OFF = носенсор), а когда поток был завершен, я вызвал setRequestedOrientation(ON) (ON = датчик). Работает как шарм.

person Christopher Perry    schedule 31.08.2010

Спасибо всем. Я изменил решение Pilot_51, чтобы убедиться, что я вернулся в предыдущее состояние. Я также внес изменение для поддержки не альбомных и не портретных экранов (но не тестировал это на таком экране).

prevOrientation = getRequestedOrientation();
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}

Затем восстановить его

setRequestedOrientation(prevOrientation);
person ProjectJourneyman    schedule 01.04.2011
comment
Хороший материал - не знаю, почему вы не использовали switch. - person ; 24.06.2011
comment
Забыл очистить и переключиться на переключатель после того, как добавил третий вариант. - person ProjectJourneyman; 27.06.2011
comment
Я обнаружил, что это работает без необходимости получать текущую конфигурацию, если у вас нет доступа к объекту действия, а только к контексту ActivityInfo.SCREEN_ORIENTATION_NOSENSOR | ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - person max4ever; 16.05.2012

Вот решение, которое работает каждый раз и сохраняет текущую ориентацию (например, при использовании Activity.Info.SCREEN_ORIENTATION_PORTRAIT устанавливается значение 0 °, но пользователь может иметь ориентацию 180 ° в качестве текущей).

// Scope: Activity

private void _lockOrientation() {
    if (super.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
    } else {
        super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
    }
}

private void _unlockOrientation() {
    super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
person Adrien Cadet    schedule 28.01.2015
comment
Стоит упомянуть: только API 18+ - person Dmitry Zaytsev; 19.05.2015

используйте ActivityInfo.SCREEN_ORIENTATION_USER, если вы хотите повернуть экран, только если он включен на устройстве.

person Pawan Maheshwari    schedule 19.09.2013

Это работает для меня. Решает проблему с разной "естественной ориентацией" планшета / телефона;)

int rotation = getWindowManager().getDefaultDisplay().getRotation();

        Configuration config = getResources().getConfiguration();
        int naturalOrientation;

        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)) {
            naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
        } else {
            naturalOrientation = Configuration.ORIENTATION_PORTRAIT;
        }

        // because getRotation() gives "rotation from natural orientation" of device (different on phone and tablet)
        // we need to update rotation variable if natural orienation isn't 0 (mainly tablets)
        if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE)
            rotation = ++rotation % 4;

        switch (rotation) {
            case Surface.ROTATION_0: //0
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case Surface.ROTATION_90: //1
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            case Surface.ROTATION_180: //2
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                break;
            case Surface.ROTATION_270: //3
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                break;
        }
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
person Naxos    schedule 30.05.2014

Я придумал решение, которое зависит от поворота дисплея, а затем определяет ориентацию устройства. Зная ориентацию, мы можем заблокировать ориентацию и отпустить ее позже, когда это необходимо. Это решение также может определить, находится ли устройство в режиме обратного ландшафта.

private void lockOrientation(){
    switch (((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation()) {


        // Portrait
        case Surface.ROTATION_0:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;


        //Landscape     
        case Surface.ROTATION_90: 
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            break;


        // Reversed landscape
        case Surface.ROTATION_270:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);             
            break;
    }
}

Позже, если нам нужно освободить ориентацию, мы можем вызвать этот метод:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
person Mansour Fahad    schedule 05.10.2014

Я считаю, что этот код легче читать.

private void keepOrientation() {

    int orientation = getResources().getConfiguration().orientation;
    int rotation = getWindowManager().getDefaultDisplay().getRotation();

    switch (rotation) {
        case Surface.ROTATION_0:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
            break;
        case Surface.ROTATION_90:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
            break;
        case Surface.ROTATION_180:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            }
            break;
        default:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            }
    }
}
person nor_miya    schedule 14.10.2014

Я обнаружил, что комбинация существующих значений поворота / ориентации необходима для охвата четырех возможностей; есть значения портрет / пейзаж и естественная ориентация устройства. Скажем, естественная ориентация устройств будет иметь значение поворота 0 градусов, когда экран находится в «естественной» портретной или альбомной ориентации. Точно так же будет значение поворота 90 градусов, когда оно находится в альбомной или портретной ориентации (обратите внимание, что это противоположно ориентации @ 0 градусов). Таким образом, значения поворота, отличные от 0 или 90 градусов, будут означать «обратную» ориентацию. Хорошо, вот код:

public enum eScreenOrientation 
{
PORTRAIT (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),
LANDSCAPE (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE),
PORTRAIT_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT),
LANDSCAPE_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE),
UNSPECIFIED_ORIENTATION (ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

    public final int activityInfoValue;

    eScreenOrientation ( int orientation )
    {
        activityInfoValue = orientation;
    }
}



public eScreenOrientation currentScreenOrientation ( )
{
    final int rotation = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();

    final int orientation = getResources().getConfiguration().orientation;
    switch ( orientation ) 
    {
    case Configuration.ORIENTATION_PORTRAIT:
        if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 )
            return eScreenOrientation.PORTRAIT;
        else
            return eScreenOrientation.PORTRAIT_REVERSE;
    case Configuration.ORIENTATION_LANDSCAPE:
        if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 )
            return eScreenOrientation.LANDSCAPE;
        else
            return eScreenOrientation.LANDSCAPE_REVERSE;
    default:
        return eScreenOrientation.UNSPECIFIED_ORIENTATION;
    }
}

public void lockScreenOrientation ( )
    throws UnsupportedDisplayException
{
    eScreenOrientation currentOrientation = currentScreenOrientation( );
    if ( currentOrientation == eScreenOrientation.UNSPECIFIED_ORIENTATION )
        throw new UnsupportedDisplayException("Unable to lock screen - unspecified orientation");
    else
        setRequestedOrientation( currentOrientation.activityInfoValue );
}

public void unlockScreenOrientation (  )
{
    setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED );
}
person Magic Hands Pellegrin    schedule 28.10.2014

Мне здесь не понравилась большая часть ответов, так как при разблокировке они установили НЕ УКАЗАНО в отличие от предыдущего состояния. ProjectJourneyman принял это во внимание, и это было здорово, но я предпочел код блокировки от Роя. Итак, я бы порекомендовал сочетание двух:

private int prevOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

private void unlockOrientation() {
    setRequestedOrientation(prevOrientation);
}

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void lockOrientation() {
    prevOrientation = getRequestedOrientation();
    Display display = getWindowManager().getDefaultDisplay();
    int rotation = display.getRotation();
    int height;
    int width;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
        height = display.getHeight();
        width = display.getWidth();
    } else {
        Point size = new Point();
        display.getSize(size);
        height = size.y;
        width = size.x;
    }
    switch (rotation) {
        case Surface.ROTATION_90:
            if (width > height)
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            else
                setRequestedOrientation(9/* reversePortait */);
            break;
        case Surface.ROTATION_180:
            if (height > width)
                setRequestedOrientation(9/* reversePortait */);
            else
                setRequestedOrientation(8/* reverseLandscape */);
            break;
        case Surface.ROTATION_270:
            if (width > height)
                setRequestedOrientation(8/* reverseLandscape */);
            else
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;
        default :
            if (height > width)
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            else
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}
person Gadzair    schedule 19.02.2015

Вы можете использовать

public void swapOrientaionLockState(){
    try{
        if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 1) {
            Display defaultDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, defaultDisplay.getRotation());
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0);
        } else {
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1);
        }

        Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, !orientationIsLocked() ? 1 : 0);

    } catch (Settings.SettingNotFoundException e){
        e.printStackTrace();
    }
}

public boolean orientationIsLocked(){
    if(canModifiSetting(mContext)){
        try {
            return Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0;
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
    }
    return false;
}

public static boolean canModifiSetting(Context context){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return Settings.System.canWrite(context);
    } else {
        return true;
    }
}
person moviehay0032    schedule 11.08.2017

используйте эту строку кода

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

в вашей деятельности oncreate метод

person Zeeshan Akhter    schedule 30.09.2013

person    schedule
comment
Не могли бы вы пояснить свой ответ? - person slfan; 23.01.2017
comment
когда у вас есть какие-то задания в фоновом режиме, просто вызовите setLockScreenOrientation (true), чтобы заблокировать ориентацию и предотвратить разрушение текущего действия для его воссоздания. когда вы убедитесь, что эти задания завершены, вызовите setLockScreenOrientation (false). - person tdjprog; 24.01.2017
comment
это лучший ответ! - person Fakher; 10.06.2017