Redémarrage de l'activité sur la rotation Android



Answers

Mise à jour pour Android 3.2 et supérieur:

Attention : À partir d'Android 3.2 (niveau API 13), la «taille de l'écran» change également lorsque l'appareil bascule entre l'orientation portrait et paysage. Ainsi, si vous souhaitez empêcher les redémarrages en raison d'un changement d'orientation lors du développement pour le niveau API 13 ou supérieur (comme indiqué par les attributs minSdkVersion et targetSdkVersion), vous devez inclure la valeur "screenSize" en plus de la valeur "orientation" . Autrement dit, vous devez déclarer android:configChanges="orientation|screenSize" . Toutefois, si votre application cible le niveau d'API 12 ou inférieur, votre activité gère toujours cette modification de configuration elle-même (cette modification de configuration ne redémarre pas votre activité, même si elle est exécutée sur un périphérique Android 3.2 ou supérieur).

Question

Dans mon application Android, lorsque je fais pivoter l'appareil ( onCreate glisser le clavier), mon Activity est redémarrée ( onCreate est appelé). Maintenant, c'est probablement comme ça que ça doit être, mais je fais beaucoup de réglages initiaux dans la méthode onCreate , donc j'ai besoin de:

  1. Mettez toute la configuration initiale dans une autre fonction afin qu'elle ne soit pas perdue lors de la rotation de l'appareil ou
  2. Faites en sorte que onCreate ne soit pas appelé à nouveau et que la mise en page s'ajuste ou
  3. Limitez l'application à juste portrait pour que onCreate ne soit pas appelé.



 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

Quelle partie du manifeste le dit "n'appelez pas onCreate() "?

Aussi, les docs de Google disent d'éviter d'utiliser android:configChanges (sauf en dernier recours) .... Mais alors les méthodes alternatives qu'ils suggèrent tous DO utilisent android:configChanges .

Il a été mon expérience que l'émulateur TOUJOURS appelle onCreate() lors de la rotation.
Mais les appareils 1-2 sur lesquels je cours le même code ... ne le font pas. (Je ne sais pas pourquoi il y aurait une différence.)




Les gens disent que vous devriez utiliser

android:configChanges="keyboardHidden|orientation"

Mais la meilleure façon de gérer la rotation sous Android est d'utiliser la classe Loader. Ce n'est pas une classe célèbre (je ne sais pas pourquoi), mais c'est bien mieux que l'AsyncTask. Je l'ai utilisé pour compléter la tâche Popular-Movies-Part-1 du cours nano degré Android.

Films populaires partie 1

Bien sûr, vous pouvez stocker les valeurs ou les vues avec onSaveInstanceState et les lire avec onRestoreInstanceState. C'est à vous de voir.




Chaque fois que l'écran est pivoté, l'activité ouverte est terminée et onCreate () est appelée à nouveau.

1 . Vous pouvez faire une chose sauvegarder l'état d'activité lorsque l'écran est tourné de sorte que, Vous pouvez récupérer toutes les anciennes choses lorsque l'onCreate () de l'activité est appelée à nouveau. Référer this lien

2. Si vous voulez empêcher le redémarrage de l'activité, placez les lignes suivantes dans votre fichier manifest.xml.

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



Je viens de découvrir cette tradition:

Pour conserver l'activité en vie grâce à un changement d'orientation et la gérer via onConfigurationChanged , la documentation et l'exemple de code ci-dessus suggèrent cela dans le fichier manifeste:

android:configChanges="keyboardHidden|orientation"

qui a l'avantage supplémentaire que cela fonctionne toujours.

La légende du bonus est que l'omission de keyboardHidden peut sembler logique, mais elle provoque des échecs dans l'émulateur (pour Android 2.1 au moins): spécifier uniquement l' orientation fera que l'émulateur appellera OnCreate et onConfigurationChanged parfois, et seulement OnCreate autres fois.

Je n'ai pas vu l'échec sur un appareil, mais j'ai entendu parler de l'émulateur échouant pour les autres. Cela vaut donc la peine de documenter.




Utilisez l'écouteur d' orientation pour effectuer différentes tâches selon différentes orientations.

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



Ajoutez cette ligne à votre manifeste: -

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

et cet extrait de l'activité: -

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



La méthode onCreate est toujours appelée même lorsque vous modifiez l' orientation d'Android. Donc déplacer toutes les fonctionnalités lourdes de cette méthode ne va pas vous aider




Il est très simple de faire les étapes suivantes:

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

Cela fonctionne pour moi:

Note: l' orientation dépend de votre requitation




ce que j'ai fait...

dans le manifeste, à la section d'activité, ajouté:

android:configChanges="keyboardHidden|orientation"

dans le code de l'activité, implémenté:

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



Après un moment d'essais et d'erreurs, j'ai trouvé une solution qui correspond à mes besoins dans la plupart des situations. Voici le code:

Configuration du manifeste:

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

Activité principale:

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

}

Et échantillon 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);
    }

}

Peut être trouvé sur github .




Corrige l'orientation de l'écran (paysage ou portrait) dans AndroidManifest.xml

android:screenOrientation="portrait" ou android:screenOrientation="landscape"

pour cela, votre méthode onResume() n'est pas appelée.




L'approche est utile mais incomplète lors de l'utilisation de Fragments.

Les fragments sont généralement recréés lors du changement de configuration. Si vous ne souhaitez pas que cela se produise, utilisez

setRetainInstance(true); dans le (s) constructeur (s) du Fragment

Cela entraînera la conservation des fragments pendant le changement de configuration.

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




La façon dont j'ai trouvé cela est d'utiliser les onRestoreInstanceState et onSaveInstanceState pour sauvegarder quelque chose dans le Bundle (même si vous n'avez pas besoin de variables sauvegardées, mettez simplement quelque chose dedans pour que le Bundle ne soit pas vide). Puis, sur la méthode onCreate , vérifiez si l'ensemble est vide, et si c'est le cas, faites l'initialisation, sinon, faites-le.




Related