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

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

  1. Поместите всю начальную настройку в другую функцию, чтобы она не была полностью потеряна при вращении устройства или
  2. Сделать так onCreate не вызывается снова, и макет просто настраивает или
  3. Ограничьте приложение только портретом, так что onCreate не вызывается.

Solutions Collecting From Web of "Перезагрузка активности при ротации Android"

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

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

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

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

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

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

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

Реагирование на изменения конфигурации [UPDATE: это устарело, поскольку API 13; См. Рекомендуемую альтернативу ]

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

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

 android:configChanges="keyboardHidden|orientation" 

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

 android:configChanges="keyboardHidden|orientation|screenSize" 

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

 @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); setContentView(R.layout.myLayout); } 

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

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

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

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

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

 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game_list); if(savedInstanceState == null){ setupCloudMessaging(); } } 

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

что я сделал…

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

 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(); } 

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

 android:configChanges 

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

 android:configChanges="orientation" 

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

 android:configChanges="keyboardHidden" 

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

 android:configChanges="keyboardHidden|orientation" 

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

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

Я только что открыл эти знания:

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

 android:configChanges="keyboardHidden|orientation" 

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

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

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

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

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

См. Здесь или здесь .

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

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

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

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

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

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

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

  android:configChanges="keyboard|keyboardHidden|orientation" 

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

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

  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() вызывает onCreate() при вращении.
Но 1-2 устройства, на которых я запускаю один и тот же код, нет. (Не знаю, почему будет какая-то разница.)

Изменения в манифесте 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(); } } 

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

 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); } 

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

Метод onCreate все еще называется даже при изменении orientation android. Поэтому перемещение всех тяжелых функций этого метода не поможет вам

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

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

Очень просто сделать следующие шаги:

 <activity android:name=".Test" android:configChanges="orientation|screenSize" android:screenOrientation="landscape" > </activity> Размер <activity android:name=".Test" android:configChanges="orientation|screenSize" android:screenOrientation="landscape" > </activity> 

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

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

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

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

Вы можете сохранить состояние активности в 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: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); } 

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

андроид: configChanges = "screenLayout | Размер экрана | ориентирование"

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

 android:configChanges="orientation" 

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

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

 android:configChanges="keyboardHidden|orientation|screenSize" 

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

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

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

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

  <activity android:name=".Youractivity" android:configChanges="orientation|screenSize"/> 

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

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

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

Вам нужно использовать метод 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"); } 

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

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

 android:configChanges="keyboardHidden|orientation" 

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

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

 <?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> Размер <?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 .

Используйте прослушиватель 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); } } 

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

 android:configChanges="orientation" 

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

Вы можете заблокировать текущую ориентацию экрана, используя этот код …

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