Redémarrage de l'activité sur Android rotation
dans mon application Android, quand je tourne l'appareil (glisser sur le clavier) puis Mon Activity
est redémarré ( onCreate
est appelé). Maintenant, c'est probablement comme ça que c'est supposé être, mais je fais beaucoup de mise en place initiale dans la méthode onCreate
, donc j'ai besoin de l'un ou l'autre:
- mettez tout le réglage initial dans une autre fonction pour qu'il ne soit pas tout perdu sur la rotation du dispositif ou
- Faire en sorte
onCreate
n'est pas appelé de nouveau et l' disposition juste ajuste ou - limiter l'application à juste portrait de sorte que
onCreate
ne s'appelle pas.
30 réponses
utilisant la classe d'Application
selon ce que vous faites dans votre initialisation, vous pourriez envisager de créer une nouvelle classe qui étend Application
et de déplacer votre code d'initialisation dans une méthode onCreate
dépassée au sein de cette classe.
public class MyApplicationClass extends Application {
@Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
le onCreate
dans la classe application n'est appelé que lorsque l'application entière est créée, de sorte que l'activité recommence sur l'orientation ou les changements de visibilité du clavier ne le déclencheront pas.
c'est une bonne pratique d'exposer l'instance de cette classe comme un singleton et d'exposer les variables d'application que vous initialisez en utilisant getters et setters.
NOTE: vous devrez spécifier le nom de votre nouvelle classe D'Application dans le Manifeste pour qu'elle soit enregistrée et utilisée:
<application
android:name="com.you.yourapp.MyApplicationClass"
réagissant à la Configuration Les changements [mise à JOUR: c'est obsolète depuis API 13; voir l'alternative recommandée ]
comme autre 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 le cadre de votre activité.
commencez par ajouter le noeud android:configChanges
au noeud manifeste de votre activité
android:configChanges="keyboardHidden|orientation"
ou pour Android 3.2 (niveau API 13) et plus récent :
android:configChanges="keyboardHidden|orientation|screenSize"
puis, dans le cadre de L'activité, outrepasser la méthode onConfigurationChanged
et appeler setContentView
pour forcer la mise en page de L'interface graphique à refaire 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 : en commençant par Android 3.2 (niveau API 13), la" taille d'écran "change également lorsque l'appareil passe de l'orientation portrait à l'orientation paysage. Ainsi, si vous voulez empêcher un redémarrage de l'exécution dû à un changement d'orientation lors du développement pour le niveau D'API 13 ou supérieur (comme déclaré par les attributs minSdkVersion et targetSdkVersion), vous devez inclure la valeur
"screenSize"
en plus de la valeur"orientation"
. C'est, vous devez déclarerandroid:configChanges="orientation|screenSize"
. Cependant, si votre application cible le niveau 12 de L'API ou un niveau inférieur, alors 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 vous utilisez un appareil Android 3.2 ou un appareil supérieur).
au lieu d'essayer d'empêcher le onCreate()
d'être tiré, essayez peut-être de vérifier le Bundle
savedInstanceState
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 le Activity
est vraiment créé, pas sur chaque changement d'orientation, Je n'exécute cette logique dans le onCreate()
que si le savedInstanceState
est nul.
sinon, je veux toujours la mise en page à redessiner 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é, mis en œuvre:
//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 l'ouverture ou la fermeture du clavier vous utiliserez:
android:configChanges="keyboardHidden"
si vous voulez gérer les deux vous pouvez juste 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 outrepassez la méthode vous pouvez passer dans les nouvelles valeurs.
Espérons que cette aide.
je viens de découvrir cette tradition:
pour maintenir l'activité en vie par un changement d'orientation, et la manipuler par onConfigurationChanged
, la documentation et l'échantillon de code au-dessus de le suggèrent dans le fichier de manifeste:
android:configChanges="keyboardHidden|orientation"
qui a l'avantage supplémentaire qu'il fonctionne toujours.
le lore bonus est que l'omission du keyboardHidden
peut sembler logique, mais il provoque des pannes dans L'émulateur (pour Android 2.1 au moins): en spécifiant seulement orientation
fera l'émulateur appeler à la fois OnCreate
et onConfigurationChanged
parfois, et seulement OnCreate
autres fois.
Je n'ai pas vu la défaillance d'un dispositif, mais j'ai entendu parler de la défaillance de l'émulateur pour les autres. Donc ça vaut la peine de le documenter.
vous pourriez également envisager d'utiliser la manière de la plateforme Android de persister les données à travers les changements d'orientation: onRetainNonConfigurationInstance()
et getLastNonConfigurationInstance()
.
cela vous permet de persister les données à travers les changements de configuration, tels que les informations que vous avez pu obtenir à partir d'un fetch serveur ou quelque chose d'autre qui a été calculé dans onCreate
ou depuis, tout en permettant à Android de re-layout votre Activity
en utilisant le fichier xml pour l'orientation maintenant en usage.
il convient de noter que ces méthodes sont maintenant dépréciées (bien qu'encore plus flexible que la manipulation orientation changer vous-même comme la plupart des solutions ci-dessus suggèrent) avec la recommandation que tout le monde passer à Fragments
et à la place d'utiliser setRetainInstance(true)
sur chaque Fragment
que vous voulez conserver.
l'approche est utile mais incomplète lorsqu'on utilise des Fragments.
Les Fragmentssont 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 provoquera la rétention de fragments lors d'un changement de configuration.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance (booléen)
j'ai simplement ajouté
android:configChanges="keyboard|keyboardHidden|orientation"
dans le fichier du manifeste et n'a pas ajouté toute méthode onConfigurationChanged
dans mon activité.
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'appelez pas onCreate()
?
Also,
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 utiliser android:configChanges
.
d'après mon expérience, l'émulateur appelle toujours onCreate()
par rotation.
Mais les 1-2 dispositifs que je exécuter le même code sur... ne le font pas.
(Je ne sais pas pourquoi il y aurait une différence.)
Ajouter cette ligne à votre manifeste :-
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
et cet extrait à 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:
android:configChanges="keyboardHidden|orientation"
Ajouts à l'intérieur de 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();
}
}
la méthode onCreate
est toujours appelée même lorsque vous changez le orientation
d'android. Donc, déplacer toutes les fonctionnalités lourdes à cette méthode ne va pas vous aider
mettez le code ci-dessous dans votre étiquette <activity>
dans Manifest.xml
:
android:configChanges="screenLayout|screenSize|orientation"
Il y a plusieurs façons de le faire:
Enregistrer L'Activité De L'État
vous pouvez sauvegarder 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);
}
et ensuite utiliser 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
}
}
changement d'orientation de la poignée par vous-même
une autre alternative est de gérer vous-même les changements d'orientation. Mais ce n'est pas considérée comme une bonne pratique.
ajoutez ceci à votre manifeste.
android:configChanges="keyboardHidden|orientation"
pour Android 3.2 et versions suivantes:
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 à l'étiquette d'activité dans votre fichier de manifeste:
android:screenOrientation="portrait"
ou de mettre en œuvre ce programme dans votre activité:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
il est très simple de faire les étapes suivantes:
<activity
android:name=".Test"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" >
</activity>
ça marche pour moi:
Note: l'orientation dépend de votre demande
la façon dont j'ai trouvé à faire ceci est d'utiliser les événements onRestoreInstanceState
et onSaveInstanceState
pour enregistrer quelque chose dans le Bundle
(même si vous n'avez pas besoin de variables enregistrées, mettez juste quelque chose là-dedans de sorte que le Bundle
n'est pas vide). Ensuite, sur la méthode onCreate
, vérifiez si le Bundle
est vide, et si c'est le cas, faites l'initialisation, sinon, faites-le.
même si ce n'est pas" la façon 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 tenir compte de l'orientation modifiée. C'est plus rapide que tout autre approche, parce que vos opinions ne doivent pas être sauvegardés et restaurés. Il fournit également une expérience plus transparente à l'utilisateur, parce que les widgets repositionnés sont exactement les mêmes widgets, juste déplacé et/ou redimensionné. Non seulement le modèle de l'état, mais voir aussi état, peut être préservé de cette manière.
RelativeLayout
peut parfois être un bon choix pour une vue qui doit se réorienter de temps en temps. Vous n'avez qu'à fournir un ensemble de param pour la mise en page de portraits et un ensemble de param pour la mise en page de paysages, avec des règles de positionnement relatives différentes sur chacun, pour chaque widget enfant. Ensuite, dans votre méthode onConfigurationChanged()
, vous passez la bonne méthode à une setLayoutParams()
pour chaque enfant. Si un enfant contrôle lui-même doit être intérieurement réorienté, vous appelez juste une méthode sur cet enfant pour effectuer la réorientation. Cet enfant appelle de la même manière des méthodes sur l'un des ses contrôles de l'enfant qui ont besoin d'une réorientation interne, et ainsi de suite.
Note: je poste cette réponse si quelqu'un dans le futur face au même problème que moi. Pour moi, la ligne suivante n'a pas été assez:
android:configChanges="orientation"
quand j'ai fait tourner l'écran, la méthode `onConfigurationChanged(Configuration newConfig) n'a pas été appelée.
Solution: j'ai également dû ajouter" screenSize " même si le problème avait à voir avec l'orientation. Donc dans le film D'Androidmanifeste.fichier xml, ajouter ceci:
android:configChanges="keyboardHidden|orientation|screenSize"
puis mettre en œuvre la méthode onConfigurationChanged(Configuration newConfig)
vous devez utiliser la méthode onsavedincestate pour stocker toute la valeur de son paramètre is has qui est bundle
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
outPersistentState.putBoolean("key",value);
}
et utilisation
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getBoolean("key");
}
pour récupérer et définir la valeur pour voir les objets il gérera les rotations de l'écran
chaque fois que l'écran est tourné, l'activité ouverte est terminée et onCreate() est appelé à nouveau.
1 . Vous pouvez faire une chose pour sauver l'état de l'activité lorsque l'écran est tourné de sorte que vous puissiez récupérer toutes les vieilles choses lorsque l'on appelle à nouveau "onCreate ()" de l'activité. Reportez-vous à ce lien
2 . Si vous voulez empêcher le redémarrage de l'activité, placez simplement les lignes suivantes dans votre manifeste.fichier xml.
<activity android:name=".Youractivity"
android:configChanges="orientation|screenSize"/>
dans la section activité du manifest
, ajouter:
android:configChanges="keyboardHidden|orientation"
ajouter cette ligne android:configChanges= " orientation / screenSize" au manifeste
Après un certain temps 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 Fragment d'échantillon:
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 .
utiliser orientation
écouter pour effectuer différentes tâches sur une orientation différente.
@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);
}
}
mettez ce code ci-dessous dans votre Activity
dans Android Manifest
.
android:configChanges="orientation"
cela ne redémarre pas votre activité lorsque vous changez d'orientation.
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.
les gens disent que vous devriez utiliser
android:configChanges="keyboardHidden|orientation"
mais la meilleure et la plus professionnelle façon de gérer la rotation dans Android est d'utiliser la classe Loader. Ce n'est pas une fameuse classe(je ne sais pas pourquoi), mais c'est mieux que l'AsyncTask. Pour plus d'informations, vous pouvez lire les tutoriels Android trouvés dans les cours Android D'Udacity.
bien sûr, comme une autre façon, vous pourriez stocker les valeurs ou les vues avec onSaveInstanceState et lire avec onRestoreInstanceState. C'est à vous vraiment.
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 objetsViewModel sont automatiquement conservés pendant les changements de configuration de sorte que les données qu'ils contiennent soient immédiatement disponibles pour l'instance suivante de l'activité ou du fragment. Lire la suite:
https://developer.android.com/topic/libraries/architecture/viewmodel