Вопрос

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

<Ол>
  • Поместите все начальные настройки в другую функцию, чтобы они не терялись при повороте устройства или
  • Сделайте так, чтобы <=> больше не вызывался, а макет просто настраивается или
  • Ограничьте приложение только портретом, чтобы <=> не вызывалось.
  • Это было полезно?

    Решение

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

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

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

    android:configChanges в классе приложения вызывается только при создании всего приложения, поэтому действие перезапускается при изменении ориентации или изменения видимости клавиатуры не вызывают его.

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

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

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

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

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

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

     <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 переопределите метод setContentView и вызовите <=>, чтобы заставить макет графического интерфейса заново выполнить в новой ориентации.

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

    Другие советы

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

      

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

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

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

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

    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, документация и пример кода выше предложить это в файле манифеста:

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

    , что дает дополнительное преимущество:

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

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

    You might also consider using the Android platform's way of persisting data across orientation changes: onRetainNonConfigurationInstance() and getLastNonConfigurationInstance().

    This allows you to persist data across configuration changes, such as information you may have gotten from a server fetch or something else that's been computed in onCreate or since, while also allowing Android to re-layout your Activity using the xml file for the orientation now in use.

    See here or here.

    It should be noted that these methods are now deprecated (although still more flexible than handling orientation change yourself as most of the above solutions suggest) with the recommendation that everyone switch to Fragments and instead use setRetainInstance(true) on each Fragment you want to retain.

    The approach is useful but is incomplete when using Fragments.

    Fragments usually get recreated on configuration change. If you don't wish this to happen, use

    setRetainInstance(true); in the Fragment's constructor(s)

    This will cause fragments to be retained during configuration change.

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

    I just simply added

         android:configChanges="keyboard|keyboardHidden|orientation"
    

    in the manifest file and did not add any onConfigurationChanged method in my activity.

    So every time the keyboard slides out or in nothing happens.

    The onCreate method is still called even when you change the orientation of android. So moving all the heavy functionality to this method is not going to help you

    It is very simple just do the following steps:

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

    This works for me :

    Note: orientation depends on your requitement

    Put the code below inside your <activity> tag in Manifest.xml:

    android:configChanges="screenLayout|screenSize|orientation"
    
     onConfigurationChanged is called when the screen rotates. 
     (onCreate is no longer called when screen rotates due to manifest, see:  
     android:configChanges)
    

    What part of the manifest tells it "don't call onCreate()"?

    Also, Google's docs say to avoid using android:configChanges (except as a last resort).... But then the alternate methods they suggest all DO use android:configChanges.

    It has been my experience that the emulator ALWAYS calls onCreate() upon rotation.
    But the 1-2 devices that I run the same code on... do not. (Not sure why there would be any difference.)

    Add this line to your manifest :-

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

    and this snippet to the activity :-

    @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
    

    Changes to be made in the Android manifest are:

    android:configChanges="keyboardHidden|orientation" 
    

    Additions to be made inside activity are:

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

    There are several ways to do this:

    Save Activity State

    You can save the activity state in 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);
    }
    

    and then use the bundle to restore the state.

    @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
        }
    }
    

    Handle orientation changes by yourself

    Another alternative is to handle the orientation changes by yourself. But this is not considered a good practice.

    Add this to your manifest file.

    android:configChanges="keyboardHidden|orientation"
    

    for Android 3.2 and later:

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

    Restrict rotation

    You can also confine your activity to portrait or landscape mode to avoid rotation.

    Add this to the activity tag in your manifest file:

            android:screenOrientation="portrait"
    

    Or implement this programmatically in your activity:

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
    

    The way I have found to do this is use the onRestoreInstanceState and the onSaveInstanceState events to save something in the Bundle (even if you dont need any variables saved, just put something in there so the Bundle isn't empty). Then, on the onCreate method, check to see if the Bundle is empty, and if it is, then do the initialization, if not, then do it.

    Even though it is not "the Android way" I have gotten very good results by handling orientation changes myself and simply repositioning the widgets within a view to take the altered orientation into account. This is faster than any other approach, because your views do not have to be saved and restored. It also provides a more seamless experience to the user, because the respositioned widgets are exactly the same widgets, just moved and/or resized. Not only model state, but also view state, can be preserved in this manner.

    RelativeLayout can sometimes be a good choice for a view that has to reorient itself from time to time. You just provide a set of portrait layout params and a set of landscaped layout params, with different relative positioning rules on each, for each child widget. Then, in your onConfigurationChanged() method, you pass the appropriate one to a setLayoutParams() call on each child. If any child control itself needs to be internally reoriented, you just call a method on that child to perform the reorientation. That child similarly calls methods on any of its child controls that need internal reorientation, and so on.

    Every time when screen is rotated, opened activity is finished and onCreate() is called again.

    1 . You can do one thing save the state of activity when screen is rotated so that, You can recover all old stuff when activity's onCreate() is called again. Refer this link

    2 . If you want to prevent restarting of the activity just place following lines in your manifest.xml file.

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

    Note: I post this answer if someone in the future face the same problem as me. For me the following line wasn't enought:

    android:configChanges="orientation"
    

    When I rotated the screen, the method `onConfigurationChanged(Configuration newConfig) did't get called.

    Solution: I also had to add "screenSize" even if the problem had to do with the orientation. So in the AndroidManifest.xml - file, add this:

    android:configChanges="keyboardHidden|orientation|screenSize"
    

    Then implement the method onConfigurationChanged(Configuration newConfig)

    you need to use the onSavedInstanceState method to store all the value to its parameter is has that is bundle

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

    and use

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

    to retrive and set the value to view objects it will handles the screen rotations

    In the activity section of the manifest, add:

    android:configChanges="keyboardHidden|orientation"
    

    Add this line in manifest : android:configChanges="orientation|screenSize"

    People are saying that you should use

    android:configChanges="keyboardHidden|orientation"
    

    But the best and most professional way to handle rotation in Android is to use the Loader class. It's not a famous class(I don't know why), but it is way better than the AsyncTask. For more information, you can read the Android tutorials found in Udacity's Android courses.

    Of course, as another way, you could store the values or the views with onSaveInstanceState and read them with onRestoreInstanceState. It's up to you really.

    After a while of trial and error, I found a solution which fits my needs in the most situations. Here is the Code:

    Manifest configuration:

    <?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>
    

    MainActivity:

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

    And sample Fragment:

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

    Can be found on github.

    Use orientation listener to perform different tasks on different 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);
        }
    }
    

    Put this below code in your Activity in Android Manifest.

    android:configChanges="orientation"
    

    This will not restart your activity when you would change orientation.

    Fix the screen orientation (landscape or portrait) in AndroidManifest.xml

    android:screenOrientation="portrait" or android:screenOrientation="landscape"

    for this your onResume() method is not called.

    One of the best component of android architechure introduce by google will fulfill your all the requirement that is ViewModel.

    That is designed to store and manage UI related data in lifecycle way plus that will allow data to survive as screen rotates

    class MyViewModel : ViewModel() {
    

    Please refer this:https://developer.android.com/topic/libraries/architecture/viewmodel

    You can lock to the current orientation of screen using this code...

    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);
            }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top