Dans mon application Android, lorsque je fais pivoter l'appareil (faites glisser le clavier), ma Activity
est redémarrée (onCreate
est appelé). Maintenant, c'est probablement ce qui est supposé être, mais je fais beaucoup de configuration initiale dans la méthode onCreate
, donc il me faut soit:
onCreate
n’est plus appelé et la mise en page s’ajuste simplement ouonCreate
ne soit pas appelé.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
remplacée dans cette classe.
public class MyApplicationClass extends Application {
@Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
La onCreate
de la classe d'application n'est appelée que lorsque l'application entière est créée. Par conséquent, l'activité redémarre à la suite d'une modification de l'orientation ou de la visibilité du clavier.
Il est judicieux 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 devez spécifier le nom de votre nouvelle classe Application dans le manifeste pour qu'elle soit enregistrée et utilisée:
<application
Android:name="com.you.yourapp.MyApplicationClass"
Réagissant aux changements de configuration _ [UPDATE: obsolète depuis l’API 13; voir l’alternative recommandée ]
Vous pouvez également demander à votre application d'écouter les événements susceptibles de provoquer un redémarrage (comme des modifications d'orientation et de visibilité du clavier) et de les gérer dans votre activité.
Commencez par ajouter le noeud Android:configChanges
au noeud du manifeste de votre activité.
Android:configChanges="keyboardHidden|orientation"
ou pour Android 3.2 (API niveau 13) et plus récent :
Android:configChanges="keyboardHidden|orientation|screenSize"
Dans l'activité, substituez ensuite la méthode onConfigurationChanged
et appelez setContentView
pour forcer la présentation de l'interface graphique à être refaite dans la nouvelle orientation.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myLayout);
}
Mise à jour pour Android 3.2 et supérieur:
Attention : à partir d'Android 3.2 (API, niveau 13), la "taille de l'écran" change également lorsque l'appareil bascule entre l'orientation portrait et l'orientation paysage. Ainsi, si vous souhaitez empêcher les redémarrages d'exécution en raison d'un changement d'orientation lors du développement pour l'API de niveau 13 ou supérieur (comme indiqué par les attributs minSdkVersion et targetSdkVersion), vous devez inclure la valeur
"screenSize"
en plus de la valeur"orientation"
. C'est-à-dire que vous devez déclarerAndroid:configChanges="orientation|screenSize"
. Toutefois, si votre application cible une API de niveau 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).
Au lieu d'essayer d'empêcher le déclenchement complet de onCreate()
, essayez peut-être de vérifier que la variable Bundle
savedInstanceState
est passée dans l'événement pour voir s'il est null ou non.
Par exemple, si une logique doit être exécutée lorsque la variable Activity
est réellement créée, et non à chaque changement d'orientation, je l'exécute uniquement dans la fonction onCreate()
uniquement si la variable savedInstanceState
est nulle.
Sinon, je veux toujours que la mise en page se redessine correctement 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.
ce que j'ai fait...
dans le manifeste, à la section activité, a 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();
}
Ce que vous décrivez est le comportement par défaut. Vous devez détecter et gérer ces événements vous-même en ajoutant:
Android:configChanges
à votre manifeste et ensuite les changements que vous voulez gérer. Donc, pour l’orientation, vous utiliseriez:
Android:configChanges="orientation"
et pour ouvrir ou fermer le clavier, vous utiliseriez:
Android:configChanges="keyboardHidden"
Si vous voulez gérer les deux, vous pouvez simplement les séparer avec la commande pipe comme suit:
Android:configChanges="keyboardHidden|orientation"
Cela déclenchera la méthode onConfigurationChanged dans l'activité que vous appelez. Si vous substituez la méthode, vous pouvez transmettre les nouvelles valeurs.
J'espère que cela t'aides.
Je viens de découvrir cette tradition:
Pour maintenir l'activité en activité lors d'un changement d'orientation et la gérer via onConfigurationChanged
, la documentation et l'exemple de code ci-dessus suggérez ceci dans le fichier Manifest:
Android:configChanges="keyboardHidden|orientation"
qui a l'avantage supplémentaire que cela fonctionne toujours.
La bonne nouvelle est qu'omettre keyboardHidden
peut sembler logique, mais cela provoque des échecs dans l'émulateur (pour Android 2.1 au moins): spécifier uniquement orientation
fera que l'émulateur appellera à la fois OnCreate
et onConfigurationChanged
parfois et seulement OnCreate
d'autres fois.
Je n'ai pas vu l'échec sur un périphérique, mais j'ai entendu parler de l'échec de l'émulateur pour d'autres. Donc, cela vaut la peine de documenter.
Vous pouvez également envisager d'utiliser la méthode de persistance des données de la plate-forme Android à travers les changements d'orientation: onRetainNonConfigurationInstance()
et getLastNonConfigurationInstance()
.
Cela vous permet de conserver les données lors des modifications de configuration, telles que les informations que vous avez peut-être obtenues à partir d'une récupération de serveur ou autre chose calculée dans onCreate
ou depuis, tout en permettant à Android de redéfinir votre Activity
en utilisant le fichier xml pour l'orientation maintenant. utilisé.
Il convient de noter que ces méthodes sont maintenant obsolètes (bien que plus souples encore que la gestion de l'orientation vous-même, comme le suggèrent la plupart des solutions ci-dessus) avec la recommandation que tout le monde passe à Fragments
et utilise plutôt setRetainInstance(true)
sur chaque Fragment
que vous souhaitez conserver.
L’approche est utile mais incomplète lors de l’utilisation de Fragments.
Les fragments sont généralement recréés lors d'un 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 lors du changement de configuration.
http://developer.Android.com/reference/Android/app/Fragment.html#setRetainInstance(boolean)
J'ai simplement ajouté
Android:configChanges="keyboard|keyboardHidden|orientation"
dans le fichier manifeste et n'a pas ajouté de méthode onConfigurationChanged
dans mon activité.
Ainsi, chaque fois que le clavier glisse ou que rien n’arrive .
Placez le code ci-dessous dans votre balise <activity>
dans Manifest.xml
:
Android:configChanges="screenLayout|screenSize|orientation"
La méthode onCreate
est toujours appelée même lorsque vous modifiez la orientation
d’Android. Donc, déplacer toutes les fonctionnalités lourdes à cette méthode ne va pas vous aider
C'est très simple, il suffit de suivre 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 demande
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 lui dit "n'appelle pas onCreate()
"?
En outre, Les docs de Google disent d'éviter d'utiliser Android:configChanges
(sauf en dernier recours) .... Mais les méthodes alternatives suggèrent tous lesDOuse Android:configChanges
.
D'après mon expérience, l'émulateur appelle TOUJOURS onCreate()
lors de la rotation.
Mais les 1-2 périphériques sur lesquels j’exécute le même code ... ne le font pas ..__ (je ne sais pas pourquoi il y aurait une différence.)
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);
}
Les modifications à apporter au manifeste Android sont les suivantes:
Android:configChanges="keyboardHidden|orientation"
Les ajouts à faire à 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();
}
}
Il y a plusieurs moyens de le faire:
Vous pouvez enregistrer l'état d'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);
}
utilisez ensuite la variable 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
}
}
Une autre alternative consiste à gérer vous-même les changements d'orientation. 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 versions ultérieures:
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
}
}
Vous pouvez également limiter votre activité au mode portrait ou paysage pour éviter la rotation.
Ajoutez ceci à la balise d'activité de 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 gérant moi-même les changements d'orientation et en repositionnant simplement les widgets dans une vue pour prendre en compte l'orientation modifiée. Ceci est plus rapide que toute autre approche, car vos vues ne doivent pas être enregistrées ni restaurées. Il offre également une expérience plus transparente à l'utilisateur, car les widgets repositionnés sont exactement les mêmes, juste déplacés et/ou redimensionnés. De cette manière, non seulement l'état du modèle, mais également l'état de la vue peuvent être préservés.
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 disposition Portrait et un ensemble de paramètres de disposition paysagers, avec différentes règles de positionnement relatif pour chaque widget enfant. Ensuite, dans votre méthode onConfigurationChanged()
, vous passez le processus approprié à un appel setLayoutParams()
sur chaque enfant. Si un contrôle enfant lui-même doit être en interne réorienté, vous appelez simplement une méthode sur cet enfant pour effectuer la réorientation. De même, cet enfant appelle des méthodes sur l'un des ses - contrôles child qui nécessitent une réorientation interne, etc.
Pour ce faire, utilisez les événements onRestoreInstanceState
et onSaveInstanceState
afin de sauvegarder quelque chose dans Bundle
(même si vous n'avez pas besoin de variables sauvegardées, insérez simplement quelque chose à l'intérieur pour que Bundle
ne soit pas vide). Ensuite, dans la méthode onCreate
, vérifiez si la variable Bundle
est vide et si c'est le cas, effectuez l'initialisation, si ce n'est pas le cas, puis exécutez-la.
Chaque fois que l'écran est pivoté, l'activité ouverte est terminée et onCreate () est appelé à nouveau.
1 . Vous pouvez faire une chose, enregistrer l’état de l’activité lorsque l’écran est pivoté afin que vous puissiez récupérer tous les anciens éléments lorsque l’activité onCreate () est appelée à nouveau . Reportez-vous this link
2 Si vous souhaitez empêcher le redémarrage de l'activité, placez simplement les lignes suivantes dans votre fichier manifest.xml.
<activity Android:name=".Youractivity"
Android:configChanges="orientation|screenSize"/>
vous devez utiliser la méthode onSavedInstanceState pour stocker toute la valeur de son paramètre est a bundle
@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");
}
rentrer et définir la valeur pour voir les objetsit gérera les rotations d’écran
Note: Je poste cette réponse si quelqu'un dans le futur fait face au même problème que moi. Pour moi, la ligne suivante n'était pas assez longue:
Android:configChanges="orientation"
Lorsque j'ai fait pivoter l'écran, la méthode `onConfigurationChanged (Configuration newConfig) n'a pas été appelée.
Solution: Je devais aussi ajouter "screenSize" même si le problème concernait l'orientation. Donc, dans le fichier AndroidManifest.xml, ajoutez ceci:
Android:configChanges="keyboardHidden|orientation|screenSize"
Puis implémentez la méthode onConfigurationChanged(Configuration newConfig)
Dans la section Activité de la manifest
, ajoutez:
Android:configChanges="keyboardHidden|orientation"
Les gens disent que vous devriez utiliser
Android:configChanges="keyboardHidden|orientation"
Mais la meilleure et la plus professionnelle des manipulations de rotation dans Android consiste à 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. Pour plus d'informations, vous pouvez lire les tutoriels Android trouvés dans les cours Android d'Udacity.
Bien entendu, vous pouvez également stocker les valeurs ou les vues avec onSaveInstanceState et les lire avec onRestoreInstanceState. C'est à vous de décider.
Ajoutez cette ligne dans le manifeste: Android:configChanges="orientation|screenSize"
Mettez ce code ci-dessous dans votre Activity
dans Android Manifest
.
Android:configChanges="orientation"
Cela ne redémarrera pas votre activité lorsque vous voudriez changer d'orientation.
Utilisez orientation
auditeur pour effectuer différentes tâches dans 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);
}
}
Fixer 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.
Après quelques essais et erreurs, j'ai trouvé une solution qui répond à 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 de 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’un des meilleurs composants d’architecture Android introduite par Google répondra à tous vos besoins, à savoir ViewModel.
Conçu pour stocker et gérer les données liées à l’interface utilisateur selon un cycle de vie plus long, ce qui permettra aux données de survivre pendant la rotation de l’écran.
class MyViewModel : ViewModel() {
Veuillez vous référer à ceci: https://developer.Android.com/topic/libraries/architecture/viewmodel
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);
}
Vous pouvez utiliser l'objet ViewModel dans votre activité.
Les objets ViewModel sont automatiquement conservés lors des modifications de configuration, de sorte que les données qu'ils contiennent sont immédiatement disponibles pour la prochaine activité ou instance de fragment .
https://developer.Android.com/topic/libraries/architecture/viewmodel