android-activity développez - Redémarrage de l'activité sur la rotation Android




créer première (25)

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.

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é.

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

Les modifications à apporter au manifeste Android sont les suivantes:

android:configChanges="keyboardHidden|orientation" 

Les ajouts à faire dans l'activité sont:

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

Placez le code ci-dessous à l'intérieur de votre <activity> dans 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)

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.)



Utilisation de la classe d'application

En fonction de ce que vous faites dans votre initialisation, vous pouvez envisager de créer une nouvelle classe qui étend Application et de déplacer votre code d'initialisation dans une méthode onCreate substituée onCreate sein de cette classe.

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

Le onCreate de la classe d'application est appelé uniquement lorsque l'application entière est créée. Par conséquent, l'activité redémarre lors de l'orientation ou les modifications de la visibilité au clavier ne la déclenchent pas.

Il est recommandé d'exposer l'instance de cette classe en tant que singleton et d'exposer les variables d'application que vous initialisez à l'aide de getters et de setters.

Remarque: vous devrez spécifier le nom de votre nouvelle classe Application dans le manifeste pour qu'il soit enregistré et utilisé:

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

Réagir aux changements de configuration [UPDATE: ceci est obsolète depuis API 13; voir l'alternative recommandée ]

Comme alternative, vous pouvez demander à votre application d'écouter les événements qui provoqueraient un redémarrage - comme l'orientation et les changements de visibilité du clavier - et de les gérer dans votre activité.

Commencez par ajouter le noeud android:configChanges noeud android:configChanges de votre activité.

android:configChanges="keyboardHidden|orientation"

ou pour Android 3.2 (niveau d'API 13) et plus récent :

android:configChanges="keyboardHidden|orientation|screenSize"

Ensuite, dans l'activité, remplacez la méthode onConfigurationChanged et appelez setContentView pour forcer la mise en page de l'interface graphique dans la nouvelle orientation.

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

Dans la section d'activité du manifest , ajoutez:

android:configChanges="keyboardHidden|orientation"

Ce que vous décrivez est le comportement par défaut. Vous devez détecter et gérer vous-même ces événements en ajoutant:

android:configChanges

à votre manifeste, puis les changements que vous voulez gérer. Donc, pour l'orientation, vous utiliseriez:

android:configChanges="orientation"

et pour le clavier étant ouvert ou fermé vous utiliseriez:

android:configChanges="keyboardHidden"

Si vous voulez gérer les deux, vous pouvez simplement les séparer avec la commande pipe comme:

android:configChanges="keyboardHidden|orientation"

Cela déclenchera la méthode onConfigurationChanged dans n'importe quelle activité que vous appelez. Si vous remplacez la méthode, vous pouvez transmettre les nouvelles valeurs.

J'espère que cela t'aides.


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).


vous devez utiliser la méthode onSavedInstanceState pour stocker toute la valeur de son paramètre est a ce paquet

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

et utilise

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

pour récupérer et définir la valeur pour afficher les objets, il va gérer les rotations de l'écran


Vous pouvez verrouiller à l'orientation actuelle de l'écran en utilisant ce 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);
        }

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

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 .


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)


Au lieu d'essayer d'empêcher le onCreate() , essayez de vérifier si le savedInstanceState est passé dans l'événement pour voir s'il est nul ou non.

Par exemple, si j'ai une logique qui doit être exécutée lorsque l' Activity est réellement créée, et non à chaque changement d'orientation, je ne lance cette logique dans onCreate() que si savedInstanceState est null.

Sinon, je souhaite toujours que la mise en page soit correctement redessinée pour l'orientation.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

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

Je ne sais pas si c'est la réponse ultime, mais cela fonctionne pour moi.


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.


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


Vous pouvez également envisager d'utiliser le mode de persistance des données de la plateforme Android pour les changements d'orientation: onRetainNonConfigurationInstance() et getLastNonConfigurationInstance() .

Cela vous permet de conserver les données à travers les changements de configuration, comme les informations que vous avez pu obtenir depuis un serveur ou d'autres qui ont été calculées dans onCreate ou depuis, tout en permettant à Android de réorganiser votre Activity utilisant le fichier xml utilisé.

Voir here ou ici .

Il convient de noter que ces méthodes sont maintenant obsolètes (bien que plus flexibles que la manipulation des changements d'orientation, comme le suggèrent la plupart des solutions ci-dessus) avec la recommandation que tout le monde passe à Fragments et utilise setRetainInstance(true) sur chaque Fragment vous voulez conserver. .


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"/>

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

Il y a plusieurs moyens de le faire:

Enregistrer l'état de l'activité

Vous pouvez enregistrer l'état de l'activité dans 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);
}

puis utilisez le bundle pour restaurer l'état.

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

Gérer les changements d'orientation par vous-même

Une autre alternative consiste à gérer les changements d'orientation par vous-même. Mais ceci n'est pas considéré comme une bonne pratique.

Ajoutez ceci à votre fichier manifeste.

android:configChanges="keyboardHidden|orientation"

pour Android 3.2 et ultérieur:

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

Restreindre la rotation

Vous pouvez également limiter votre activité au mode portrait ou paysage pour éviter la rotation.

Ajoutez ceci à la balise d'activité dans votre fichier manifeste:

        android:screenOrientation="portrait"

Ou implémentez ceci par programme dans votre activité:

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

Même si ce n'est pas "la manière Android", j'ai obtenu de très bons résultats en manipulant les changements d'orientation moi-même et en repositionnant simplement les widgets dans une vue pour prendre en compte l'orientation modifiée. C'est plus rapide que toute autre approche, car vos vues ne doivent pas être sauvegardées et restaurées. Il fournit également une expérience plus transparente à l'utilisateur, car les widgets repositionnés sont exactement les mêmes widgets, juste déplacés et / ou redimensionnés. Non seulement l'état du modèle, mais aussi l'état d'affichage, peuvent être préservés de cette manière.

RelativeLayout peut parfois être un bon choix pour une vue qui doit se réorienter de temps en temps. Vous fournissez simplement un ensemble de paramètres de mise en page du portrait et un ensemble de paramètres de mise en page paysagés, avec des règles de positionnement relatives différentes pour chaque widget enfant. Ensuite, dans votre méthode onConfigurationChanged() , vous passez la méthode appropriée à un appel setLayoutParams() sur chaque enfant. Si un contrôle enfant lui-même doit être réorienté en interne , vous appelez simplement une méthode sur cet enfant pour effectuer la réorientation. Cet enfant appelle également des méthodes sur l'un de ses contrôles enfants qui nécessitent une réorientation interne, et ainsi de suite.


Ajouter cette ligne android: configChanges = "orientation | screenSize" dans le manifeste


Vous pouvez simplement définir "focusable" et "focusable en mode tactile" sur la valeur true du premier TextView de la layout . De cette façon, lorsque l'activité commencera, le TextView sera concentré mais, en raison de sa nature, rien ne sera concentré sur l'écran et, bien sûr, aucun clavier ne sera affiché ...







android rotation android-activity