Перезапуск активности при ротации Android

1381

В моем приложении для Android, когда я поворачиваю устройство (выдвигаю клавиатуру), то мой Activityперезагружается ( onCreateназывается). Теперь, вероятно, так и должно быть, но я делаю много начальных настроек в onCreateметоде, поэтому мне нужно либо:

  1. Поместите все начальные настройки в другую функцию, чтобы они не терялись при повороте устройства или
  2. Сделайте так, чтобы onCreateон не вызывался снова, а макет просто настраивается или
  3. Ограничьте приложение только портретом, чтобы onCreateон не вызывался.
Исаак Уоллер
источник
4
В этом посте также есть довольно полное объяснение того, как сохранить длительные асинхронные задачи во время изменений конфигурации действий !
Адриан Монк
3
Это не прямой ответ, так как другие уже ответили, но я приглашаю вас взглянуть на LogLifeCycle, чтобы понять, что происходит в ваших приложениях для Android относительно жизненных циклов.
Сниколас

Ответы:

965

Использование класса приложения

В зависимости от того, что вы делаете при инициализации, вы можете рассмотреть возможность создания нового класса, который расширяет Applicationи перемещает ваш код инициализации в переопределенный onCreateметод внутри этого класса.

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

Класс onCreateв приложении вызывается только при создании всего приложения, поэтому действие перезапускается при изменении ориентации, иначе изменения видимости клавиатуры не вызовут его.

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

ПРИМЕЧАНИЕ. Вам нужно будет указать имя вашего нового класса приложения в манифесте, чтобы он был зарегистрирован и использован:

<application
    android:name="com.you.yourapp.MyApplicationClass"

Реакция на изменения конфигурации [ОБНОВЛЕНИЕ: это устарело с API 13; см. рекомендуемый вариант ]

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

Начните с добавления android:configChangesузла в узел манифеста вашей деятельности

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

или для Android 3.2 (уровень API 13) и новее :

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize"
      android:label="@string/app_name">

Затем в Activity переопределите onConfigurationChangedметод и вызовите, setContentViewчтобы принудительно сделать макет графического интерфейса в новой ориентации.

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}
Рето Мейер
источник
17
Я не думаю, что второй подход работает. Я попробовал это; одно действие с EditText. Я написал там какой-то текст, изменил ориентацию и текст пропал / сбросился.
Тед
231
Мы надеемся, что в будущем мы увидим метод onRotate (). Откровенно говоря, разочарование вызывает необходимость беспокоиться о таких вещах.
Келли Саттон
84
Обратите внимание, что Android Dev Guide предостерегает от использования этого: Примечание: использование ( android:configChanges) следует избегать и использовать только в качестве крайней меры. Пожалуйста, прочитайте Обработка изменений времени выполнения для получения дополнительной информации о том, как правильно обрабатывать перезапуск из-за изменения конфигурации. Вместо этого, чтобы сохранить данные в событиях вращения, они предпочитают использовать onSaveInstanceState Bundle; или как @ Jon-O упоминает , onRetainNonConfigurationInstance.
Джеффро
19
Это плохое решение, потому что оно реагирует только на известные на данный момент изменения конфигурации. В более новых версиях Android могут произойти другие изменения конфигурации, которые не будет перехвачен этим кодом (поскольку он должен перечислять все изменения конфигурации в манифесте). Решение сохранения состояния с onRetainNonConfigurationChangesболее отказоустойчивым и прямым.
Bananeweizen
16
Я думаю, что вы должны добавить это обновление на 3.2 к своему ответу, это очень важно (только что столкнулся с этой проблемой), и это может быть упущено.
большие камни
185

Обновление для Android 3.2 и выше:

Внимание : Начиная с Android 3.2 (уровень API 13), «размер экрана» также изменяется, когда устройство переключается между книжной и альбомной ориентацией. Таким образом, если вы хотите предотвратить перезапуск среды выполнения из-за изменения ориентации при разработке для API уровня 13 или выше (как объявлено атрибутами minSdkVersion и targetSdkVersion), вы должны добавить "screenSize"значение в дополнение к "orientation"значению. То есть ты должен объявить android:configChanges="orientation|screenSize". Однако, если ваше приложение предназначено для уровня API 12 или ниже, то ваша активность всегда сама обрабатывает это изменение конфигурации (это изменение конфигурации не перезапускает вашу активность, даже при работе на устройстве Android 3.2 или выше).

Горм
источник
1
Спасибо за это разъяснение, поскольку вышеприведенный комментарий почти заставил меня разобраться в этом. В настоящее время я нацеливаюсь на API 8, и мой код не имеет screenSize в configChanges и может подтвердить, что он работает нормально (без переориентации) на моем устройстве, на котором работает ICS.
Карл
Спасибо за указание на это, у меня был установлен только android: configChanges = "direction | screenSize", и переключение ориентации воссоздало мою активность, и я не мог понять, почему!
Кристофер Перри
5
Добавление Android: configChanges следует использовать только в качестве крайней меры . Подумайте об использовании Fragmentsи setRetainInstanceвместо.
Саймон Форсберг
Ключевой момент screenSizeдля Android 3.2 и выше, который решил мою проблему, спасибо!
fantouch
127

Вместо того, чтобы пытаться onCreate()полностью запретить запуск, возможно, попробуйте проверить, было ли Bundle savedInstanceStateоно передано в событие, чтобы увидеть, является ли оно нулевым или нет.

Например, если у меня есть какая-то логика, которая должна запускаться, когда Activityона действительно создана, а не при каждом изменении ориентации, я запускаю эту логику onCreate()только в том случае, если savedInstanceStateона нулевая.

В противном случае я все еще хочу, чтобы макет правильно перерисовывался для ориентации.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

не уверен, что это окончательный ответ, но он работает для меня.

туманностей
источник
6
и где ты на самом деле спасение государства?
Эвокс
5
кажется, это работает для меня, и это, безусловно, самый простой метод. я заметил, что вы получили только 4 взлета за это (5 включая мое) против 373 за идею о создании подкласса Application, которая мне кажется гораздо более сложной. есть ли недостатки этого метода?
Steveh
4
Это решение сработало для меня. я был в состоянии Intent serverintent = new Intent(MainActivity.this, MessageListener.class);и startService(serverintent);создать serverSocket = new ServerSocket(0xcff2);и Socket client = serverSocket.accept();с BufferedReader(new InputStreamReader(client.getInputStream()));и мог вращать мой андроид и поддерживать соединение клиент / сервер активным, но иметь графический интерфейс поворота. Согласно руководству, saveInstanceState инициализируется после завершения последней операции.
Фред Ф
3
Я не понимаю, в чем подвох? Это прекрасно работает, и с гораздо меньшей сложностью, чем любое другое решение.
RTF
3
Это правильный способ сделать это в Android. Другие способы в основном ловить вращение с помощью configChanges и всего того, что является громоздким, сложным и ненужным.
LukeWaggoner
99

что я сделал...

в манифесте к разделу активности добавлено:

android:configChanges="keyboardHidden|orientation"

В коде для деятельности реализовано:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}
Кто-то где-то
источник
3
чтобы уточнить: с моей реализацией у вас теперь может быть инициализация переменной в onCreate () и onConfigurationChanged () будет просто вызываться для поворота экрана. Ваши переменные теперь изолированы от поворотов экрана ;-) nice and ez
Someone Somewhere
2
Я сделал все так, как описано здесь, но я получаю NullPointerException, когда я пытаюсь нажать кнопку после изменения ориентации. Что может быть не так?
Finnboy11
5
помните, что моему ответу уже 3 года, а Android продолжает развиваться ... Саймон - у вас есть ссылка на пример кода? Это то, что нужно людям.
Кто-то где-то
3
При предупреждении против Android: configChanges, @ SimonAndréForsberg фактически просто перефразирует документы по Android . Обработка изменений времени выполнения содержит более подробную информацию об альтернативах (включая пример кода).
Лейф Арне Сторсет
67

То, что вы описываете, является поведением по умолчанию. Вы должны обнаружить и обработать эти события самостоятельно, добавив:

android:configChanges

в ваш манифест, а затем изменения, которые вы хотите обработать. Так что для ориентации вы бы использовали:

android:configChanges="orientation"

и для открытия или закрытия клавиатуры вы должны использовать:

android:configChanges="keyboardHidden"

Если вы хотите обработать оба, вы можете просто разделить их командой pipe, например:

android:configChanges="keyboardHidden|orientation"

Это вызовет метод onConfigurationChanged в любой операции, которую вы вызываете. Если вы переопределите метод, вы можете передать новые значения.

Надеюсь это поможет.

GregD
источник
2
@GregD Я знаю, поэтому сейчас самое время обновить его, чтобы отразить сегодняшнюю ситуацию. Учитывая количество голосов, поднятых этим вопросом, на него все еще ссылаются другие вопросы по SO.
Саймон Форсберг,
48

Я только что обнаружил это знание:

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

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

который имеет дополнительное преимущество, что он всегда работает.

Суть в том, что опускание keyboardHiddenможет показаться логичным, но это приводит к сбоям в эмуляторе (по крайней мере, для Android 2.1): указание только orientationприведет к вызову эмулятора как OnCreateи onConfigurationChangedиногда, так и только в OnCreateдругих случаях.

Я не видел сбой на устройстве, но я слышал о сбое эмулятора для других. Так что стоит документировать.

Людвикас Букис
источник
14
Внимание: Начиная с Android 3.2 (уровень API 13), «размер экрана» также изменяется, когда устройство переключается между книжной и альбомной ориентацией. Таким образом, если вы хотите предотвратить перезапуск среды выполнения из-за изменения ориентации при разработке для API уровня 13 или выше: android: configChanges = "direction | keyboardHidden | screenSize"
Geltrude
Да, эмулятор сосет много времени. Вы не можете полагаться на него, чтобы точно сообщать об изменениях конфигурации.
Игорь Ганапольский
Добавление Android: configChanges следует использовать только в качестве крайней меры . Подумайте об использовании Fragmentsи setRetainInstanceвместо.
Саймон Форсберг
38

Вы можете также рассмотреть возможность использования платформы Android для сохранения данных при изменении ориентации: onRetainNonConfigurationInstance()иgetLastNonConfigurationInstance() .

Это позволяет вам сохранять данные при изменениях конфигурации, такие как информация, которую вы, возможно, получили из выборки сервера или чего-то еще, что было вычислено в том onCreateили ином периоде , а также позволяет Android изменять макет вашегоActivity используя файл xml для ориентации, используемой в настоящее время. ,

Смотрите здесь или здесь .

Следует отметить, что эти методы в настоящее время устарели (хотя они по-прежнему более гибкие, чем управление изменением ориентации самостоятельно, как предлагает большинство из приведенных выше решений) с рекомендацией, чтобы все переключались Fragmentsи вместо этого использовали setRetainInstance(true)каждый из них, который Fragmentвы хотите сохранить.

Джон О
источник
3
Я действительно думаю, что Fragments и setRetainInstance - лучший способ (и рекомендуемый Google способ) сделать это, +1 для вас и -1 для всех остальных. Добавление андроида: configChanges следует использовать только в качестве крайней меры
Саймон Форсберг
32

Подход полезен, но неполон при использовании фрагментов.

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

setRetainInstance(true); в конструкторе (ах) фрагмента

Это приведет к тому, что фрагменты будут сохранены во время изменения конфигурации.

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)

Абдо
источник
7
Согласовано. С последним Android API, кажется, фрагменты являются правильным способом справиться с этим. Я сам еще не пробовал, но из того, что я собрал, читая эту страницу , вы в основном перемещаете 99% того, что вы использовали для реализации в действии, в подкласс фрагмента, а затем добавляете этот фрагмент в действие. Это действие все равно будет уничтожено и воссоздано при повороте экрана, но вы можете указать android не уничтожать фрагмент, используя setRetainInstance()метод @Abdo, упомянутый выше.
brianmearns
25

Я просто добавил

     android:configChanges="keyboard|keyboardHidden|orientation"

в файле манифеста и не добавил ни одного onConfigurationChangedметода в моей деятельности.

Поэтому каждый раз, когда клавиатура выдвигается или ничего не происходит .

bass.t
источник
добавил <application ...android:configChanges="keyboard|keyboardHidden|orientation">и работает. Мои настройки в build.gradle:minSdkVersion 15, compileSdkVersion 23, buildToolsVersion "23.0.2"
Младший Mayhé
19

onCreateМетод еще называют , даже если вы измените orientationна андроид. Таким образом, перенос всей тяжелой функциональности на этот метод не поможет вам

ганеш кришнан
источник
18

Поместите код ниже внутри вашего <activity>тега в Manifest.xml:

android:configChanges="screenLayout|screenSize|orientation"
Вайшали Сутария
источник
17
 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

Какая часть манифеста говорит «не звони onCreate()»?

Кроме того, документы Google говорят, что следует избегать использования android:configChanges(кроме как в крайнем случае) .... Но тогда альтернативные методы, которые они предлагают, все ДОЛЖНЫ использовать android:configChanges.

По моему опыту, эмулятор ВСЕГДА вызывает onCreate()по очереди.
Но на 1-2 устройствах, на которых я запускаю один и тот же код ... нет. (Не уверен, почему будет какая-либо разница.)

Кэрол
источник
16

Это очень просто, просто выполните следующие шаги:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

Это работает для меня:

Примечание: ориентация зависит от вашего требования

ManiTeja
источник
15

В манифесте Android необходимо внести следующие изменения:

android:configChanges="keyboardHidden|orientation" 

Дополнения, которые будут сделаны внутри деятельности:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
Саммит Пандей
источник
15

Добавьте эту строку в свой манифест: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

и этот фрагмент к деятельности: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
Парин Парих
источник
14

Есть несколько способов сделать это:

Сохранить состояние активности

Вы можете сохранить состояние активности в onSaveInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

а затем используйте bundleдля восстановления состояния.

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

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

Обращайтесь с изменениями ориентации самостоятельно

Другая альтернатива - справиться с изменениями ориентации самостоятельно. Но это не считается хорошей практикой.

Добавьте это в свой файл манифеста.

android:configChanges="keyboardHidden|orientation"

для Android 3.2 и более поздних версий:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

Ограничить вращение

Вы также можете ограничить свою деятельность портретным или ландшафтным режимом, чтобы избежать вращения.

Добавьте это к тегу активности в вашем файле манифеста:

        android:screenOrientation="portrait"

Или внедрите это программно в свою деятельность:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Piyush
источник
11

Способ я нашел , чтобы это сделать , это использовать onRestoreInstanceStateи onSaveInstanceStateсобытия , чтобы сохранить что - то в Bundle(даже если вы не нужны какие - либо переменные сохраняются, просто положить что - то в там , так что Bundleне пуста). Затем в onCreateметоде проверьте, Bundleявляется ли объект пустым, и если он есть, то выполните инициализацию, если нет, то сделайте это.

Shaun
источник
11

Несмотря на то, что это не «способ Android», я получил очень хорошие результаты, самостоятельно обрабатывая изменения ориентации и просто перемещая виджеты в пределах вида, чтобы принять во внимание измененную ориентацию. Это быстрее, чем любой другой подход, потому что ваши представления не должны быть сохранены и восстановлены. Это также обеспечивает более плавное взаимодействие с пользователем, поскольку видоизмененные виджеты - это точно такие же виджеты, только что перемещенные и / или измененные. Таким образом можно сохранить не только состояние модели, но и состояние просмотра.

RelativeLayoutиногда может быть хорошим выбором для представления, которое время от времени должно переориентироваться. Вы просто предоставляете набор параметров портретного макета и набор параметров ландшафтного макета с различными правилами относительного позиционирования для каждого дочернего виджета. Затем в своем onConfigurationChanged()методе вы передаете соответствующий setLayoutParams()вызов каждому ребенку. Если какой-либо дочерний элемент управления должен быть внутренне переориентирован, вы просто вызываете метод для этого дочернего элемента, чтобы выполнить переориентацию. Этот дочерний процесс аналогичным образом вызывает методы любого из своих дочерних элементов управления, которые нуждаются во внутренней переориентации и т. Д.

деревенщина
источник
Я хотел бы увидеть пример этого кода, кажется блестящим!
Энрике де Соуза
8

Каждый раз, когда экран поворачивается, открытое действие заканчивается и снова вызывается onCreate ().

1 Вы можете сделать одно, сохранить состояние активности при повороте экрана, чтобы вы могли восстановить все старые вещи, когда функция onCreate () вызывается снова. Отослать это ссылки

2 Если вы хотите предотвратить перезапуск действия, просто поместите следующие строки в файл manifest.xml.

  <activity android:name=".Youractivity"
  android:configChanges="orientation|screenSize"/>
Mansuu ....
источник
7

вам нужно использовать метод onSavedInstanceState, чтобы сохранить все значения для его параметра, который имеет связку

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

и использовать

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

чтобы получить и установить значение для просмотра объектов, он будет обрабатывать поворот экрана

Котесвара Д.К.
источник
Для этого нужен уровень API 22
Мохаммад Афраштех
6

Примечание: я публикую этот ответ, если в будущем кто-то столкнется с той же проблемой, что и я. Для меня не было достаточно следующей строки:

android:configChanges="orientation"

Когда я повернул экран, метод `onConfigurationChanged (Configuration newConfig) не был вызван.

Решение: мне также пришлось добавить «screenSize», даже если проблема была связана с ориентацией. Поэтому в файле AndroidManifest.xml добавьте следующее:

android:configChanges="keyboardHidden|orientation|screenSize"

Затем реализовать метод onConfigurationChanged(Configuration newConfig)

iHank
источник
5

В разделе действий manifestдобавьте:

android:configChanges="keyboardHidden|orientation"
Ричард К Малехо
источник
5

Добавьте эту строку в манифест: android:configChanges="orientation|screenSize"

Викрамсинх Гайквад
источник
4

Люди говорят, что вы должны использовать

android:configChanges="keyboardHidden|orientation"

Но лучший и самый профессиональный способ справиться с вращением в Android - это использовать класс Loader. Это не известный класс (я не знаю почему), но он намного лучше, чем AsyncTask. Для получения дополнительной информации вы можете прочитать учебники по Android, которые можно найти в курсах по Android от Udacity.

Конечно, в качестве другого способа вы можете сохранить значения или представления с помощью onSaveInstanceState и прочитать их с помощью onRestoreInstanceState. Это зависит от вас на самом деле.

Тео
источник
Да, давайте добавим куски дополнительного кода, чтобы выглядеть «профессионально». Или просто придерживаться быстрого, простого, верного и проверенного способа сделать это с помощью атрибута configurationChanges.
AndroidDev
3

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

Конфигурация манифеста:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

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

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Основная деятельность:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


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


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


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


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

И образец фрагмента:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

Можно найти на GitHub .

Мартин Пфеффер
источник
3

Используйте orientationслушателя для выполнения разных задач с различной ориентацией.

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}
Акшай Паливал
источник
3

Поместите этот код ниже в ваш Activityвход Android Manifest.

android:configChanges="orientation"

Это не возобновит вашу деятельность, когда вы измените ориентацию.

Пратик Даса
источник
2
@ Mavamaarten Вероятно, потому что, как указывали другие, это плохая практика, и десять других ответов уже охватили это.
MikkoP
3

Исправьте ориентацию экрана (альбомную или книжную) в AndroidManifest.xml

android:screenOrientation="portrait" или android:screenOrientation="landscape"

для этого ваш onResume()метод не вызывается.

Бражендра Пандей
источник
5
как, чёрт возьми, починить что-то - ответ? Почему наши устройства могут вращаться, если мы блокируем пользователей, используя его?
Райнхерд
3

Один из лучших компонентов архитектуры Android, представленный Google, удовлетворит все ваши требования, а именно ViewModel.

Это предназначено для хранения и управления данными, относящимися к пользовательскому интерфейсу, в режиме жизненного цикла, а также позволит выживать данным при повороте экрана

class MyViewModel : ViewModel() {

Пожалуйста, обратитесь это: https://developer.android.com/topic/libraries/architecture/viewmodel

Android Geek
источник
1

Вы можете использовать объект ViewModel в своей деятельности.

Объекты ViewModel автоматически сохраняются во время изменений конфигурации, поэтому данные, которые они хранят, сразу же становятся доступны для следующего действия или экземпляра фрагмента. Читать далее:

https://developer.android.com/topic/libraries/architecture/viewmodel

Грегори Буйко
источник