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




15 Answers

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

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

android detect screen rotation

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

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



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

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

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



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

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

android:configChanges="keyboardHidden|orientation"

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

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

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




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

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

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

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

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




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



Поместите код ниже в свой <activity> в Manifest.xml :

android:configChanges="screenLayout|screenSize|orientation"



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

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

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

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




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

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




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

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

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 .




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

android:configChanges="orientation"

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




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

android:configChanges="keyboardHidden|orientation"

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

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




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

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

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




Related