Actividad reiniciar en rotación Android

En mi aplicación Android, cuando giro el dispositivo ( onCreate el teclado), entonces mi Activity se reinicia (se llama a onCreate ). Ahora, esta es probablemente la forma en que se supone que debe ser, pero realizo una gran cantidad de configuración inicial en el método onCreate , por lo que necesito:

  1. Ponga toda la configuración inicial en otra función para que no todo se pierda en la rotación del dispositivo o
  2. Haga que sea así onCreate no se llama de nuevo y el diseño simplemente se ajusta o
  3. Limite la aplicación a solo retratos para que onCreate no se llame.

Usando la clase de aplicación

Dependiendo de lo que esté haciendo en su inicialización, podría considerar crear una nueva clase que extienda la Application y mover su código de inicialización a un método onCreate anulado dentro de esa clase.

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

El onCreate en la clase de la aplicación solo se llama cuando se crea toda la aplicación, por lo que la actividad se reinicia en la orientación o los cambios de visibilidad del teclado no la activarán.

Es una buena práctica exponer la instancia de esta clase como singleton y exponer las variables de la aplicación que está inicializando utilizando getters y setters.

NOTA: Deberá especificar el nombre de su nueva clase de aplicación en el manifiesto para que se registre y use:

  

Reaccionando a los cambios de configuración [ACTUALIZACIÓN: esto está en desuso desde la API 13; ver la alternativa recomendada ]

Como alternativa adicional, puede hacer que su aplicación escuche los eventos que provocarían un reinicio, como la orientación y los cambios de visibilidad del teclado, y los manejaría dentro de su Actividad.

Comience agregando el nodo android:configChanges nodo de manifestación de su actividad

 android:configChanges="keyboardHidden|orientation" 

o para Android 3.2 (API nivel 13) y más nuevo :

 android:configChanges="keyboardHidden|orientation|screenSize" 

Luego, dentro de la Actividad, anule el método onConfigurationChanged y llame a setContentView para forzar el diseño de la GUI para que se vuelva a realizar en la nueva orientación.

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

Actualización para Android 3.2 y superior:

Precaución : a partir de Android 3.2 (nivel de API 13), el “tamaño de pantalla” también cambia cuando el dispositivo cambia entre la orientación vertical y horizontal. Por lo tanto, si desea evitar que se reinicie el tiempo de ejecución debido al cambio de orientación cuando se desarrolla para API nivel 13 o superior (según lo declarado por los atributos minSdkVersion y targetSdkVersion), debe incluir el valor "screenSize" además del valor de "orientation" . Es decir, debe declarar android:configChanges="orientation|screenSize" . Sin embargo, si su aplicación se dirige al nivel API 12 o inferior, su actividad siempre maneja esta configuración por sí misma (este cambio de configuración no reinicia su actividad, incluso cuando se ejecuta en un dispositivo con Android 3.2 o superior).

En lugar de tratar de evitar que onCreate() por completo, tal vez intente comprobar que Bundle savedInstanceState se pase al evento para ver si es nulo o no.

Por ejemplo, si tengo una lógica que se debe ejecutar cuando la Activity realmente se crea, no en cada cambio de orientación, solo ejecuto esa lógica en onCreate() solo si el estado de savedInstanceState es nulo.

De lo contrario, todavía quiero que el diseño vuelva a dibujarse correctamente para la orientación.

 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game_list); if(savedInstanceState == null){ setupCloudMessaging(); } } 

no estoy seguro de si esta es la respuesta definitiva, pero funciona para mí.

lo que hice…

en el manifiesto, a la sección de actividad, agregó:

 android:configChanges="keyboardHidden|orientation" 

en el código para la actividad, implementado:

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

Lo que describes es el comportamiento predeterminado. Debe detectar y manejar estos eventos usted mismo al agregar:

 android:configChanges 

a su manifiesto y luego a los cambios que desea manejar. Entonces, para la orientación, usarías:

 android:configChanges="orientation" 

y para abrir o cerrar el teclado, usaría:

 android:configChanges="keyboardHidden" 

Si quieres manejar ambos, puedes separarlos con el comando pipe como:

 android:configChanges="keyboardHidden|orientation" 

Esto activará el método onConfigurationChanged en cualquier actividad que llame. Si anula el método, puede pasar los nuevos valores.

Espero que esto ayude.

Acabo de descubrir esta historia:

Para mantener la Actividad activa a través de un cambio de orientación, y manejarla a través onConfigurationChanged , la documentación y el ejemplo de código anterior sugieren esto en el archivo de Manifiesto:

 android:configChanges="keyboardHidden|orientation" 

que tiene el beneficio adicional de que siempre funciona.

El conocimiento extra es que omitir el keyboardHidden puede parecer lógico, pero causa fallas en el emulador (al menos para Android 2.1): especificar solo la orientation hará que el emulador llame a OnCreate y onConfigurationChanged veces, y solo a OnCreate otras veces.

No he visto la falla en un dispositivo, pero he escuchado que el emulador falla para otros. Entonces vale la pena documentar.

También podría considerar usar la forma de datos persistentes de la plataforma Android en los cambios de orientación: onRetainNonConfigurationInstance() y getLastNonConfigurationInstance() .

Esto le permite conservar datos a través de cambios de configuración, como la información que puede haber obtenido de una búsqueda del servidor u otra cosa que se haya calculado en onCreate o since, y que permita a Android volver a diseñar su Activity utilizando el archivo xml para la orientación ahora en uso.

Mira aquí o aquí .

Se debe tener en cuenta que estos métodos ahora están en desuso (aunque son más flexibles que la orientación al cambiarse como lo sugieren la mayoría de las soluciones anteriores) con la recomendación de que todos cambien a Fragments y en su lugar usen setRetainInstance(true) en cada Fragment que desee retener .

El enfoque es útil pero está incompleto cuando se usan Fragmentos.

Los fragmentos generalmente se vuelven a crear en el cambio de configuración. Si no desea que esto suceda, use

setRetainInstance(true); en el (los) constructor (es) del Fragmento

Esto causará que los fragmentos sean retenidos durante el cambio de configuración.

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

Simplemente agregué

  android:configChanges="keyboard|keyboardHidden|orientation" 

en el archivo manifest y no onConfigurationChanged ningún método onConfigurationChanged en mi actividad.

Entonces, cada vez que el teclado se desliza o no pasa nada .

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

¿Qué parte del manifiesto dice que “no llame a onCreate() “?

Además, los documentos de Google dicen que evite usar android:configChanges (excepto como último recurso) …. Pero luego los métodos alternativos que sugieren todos DO usan android:configChanges .

Según mi experiencia, el emulador SIEMPRE llama a onCreate() al momento de la rotación.
Pero los 1-2 dispositivos con los que ejecuto el mismo código … no. (No estoy seguro de por qué habría alguna diferencia).

Agregue esta línea a su manifiesto: –

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

y este fragmento de la actividad: –

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

Los cambios que se realizarán en el manifiesto de Android son:

 android:configChanges="keyboardHidden|orientation" 

Las adiciones que se realizarán dentro de la actividad son:

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

Hay varias formas de hacer esto:

Guardar estado de la actividad

Puede guardar el estado de la actividad en onSaveInstanceState .

 @Override public void onSaveInstanceState(Bundle outState) { /*Save your data to be restred here Example : outState.putLong("time_state", time); , time is a long variable*/ super.onSaveInstanceState(outState); } 

y luego usa el bundle para restaurar el estado.

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

Maneje los cambios de orientación por usted mismo

Otra alternativa es manejar los cambios de orientación por ti mismo. Pero esto no se considera una buena práctica.

Agregue esto a su archivo de manifiesto.

 android:configChanges="keyboardHidden|orientation" 

para Android 3.2 y posterior:

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

Restrinja la rotación

También puede limitar su actividad al modo vertical u horizontal para evitar la rotación.

Agregue esto a la etiqueta de actividad en su archivo de manifiesto:

  android:screenOrientation="portrait" 

O implemente esto programáticamente en su actividad:

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

El método onCreate aún se llama aunque cambie la orientation de Android. Así que mover toda la funcionalidad pesada a este método no te va a ayudar

Coloque el código siguiente dentro de su etiqueta en Manifest.xml :

 android:configChanges="screenLayout|screenSize|orientation" 

La forma en que lo he encontrado es usar los onRestoreInstanceState y onSaveInstanceState para guardar algo en el Bundle (incluso si no necesita guardar ninguna variable, simplemente ponga algo allí para que el Bundle no esté vacío). Luego, en el método onCreate , verifique si el Bundle está vacío, y si lo está, luego realice la inicialización, de lo contrario, hágalo.

Aunque no es “el modo Android”, obtuve muy buenos resultados al manejar los cambios de orientación yo mismo y simplemente reposicionar los widgets dentro de una vista para tener en cuenta la orientación alterada. Esto es más rápido que cualquier otro enfoque, porque sus vistas no tienen que ser guardadas y restauradas. También proporciona una experiencia más fluida para el usuario, porque los widgets respositados son exactamente los mismos widgets, simplemente se mueven y / o cambian de tamaño. No solo el estado del modelo, sino también el estado de vista, pueden conservarse de esta manera.

RelativeLayout veces puede ser una buena opción para una vista que tiene que reorientarse de vez en cuando. Solo debe proporcionar un conjunto de parámetros de diseño de retrato y un conjunto de parámetros de diseño paisajístico, con diferentes reglas de posicionamiento relativo en cada uno, para cada widget hijo. Luego, en su método onConfigurationChanged() , pasa el apropiado a una llamada setLayoutParams() en cada elemento secundario. Si algún control secundario necesita reorientarse internamente , solo debe llamar a un método sobre ese niño para realizar la reorientación. Ese niño también llama métodos a cualquiera de sus controles secundarios que necesitan una reorientación interna, y así sucesivamente.

Es muy simple solo haz los siguientes pasos:

   

Esto funciona para mí:

Nota: la orientación depende de su requerimiento

Nota: publico esta respuesta si alguien en el futuro enfrenta el mismo problema que yo. Para mí, la siguiente línea no fue suficiente:

 android:configChanges="orientation" 

Cuando giré la pantalla, no se llamó al método `onConfigurationChanged (Configuration newConfig).

Solución: también tuve que agregar “screenSize” incluso si el problema tenía que ver con la orientación. Entonces, en el archivo AndroidManifest.xml -, agregue esto:

 android:configChanges="keyboardHidden|orientation|screenSize" 

A continuación, implemente el método onConfigurationChanged(Configuration newConfig)

necesita usar el método onSavedInstanceState para almacenar todo el valor de su parámetro es tiene ese paquete

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

y use

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

para recuperar y establecer el valor para ver objetos, manejará las rotaciones de la pantalla

Cada vez que se gira la pantalla, la actividad abierta finaliza y se llama de nuevo a onCreate ().

1. Puede hacer una cosa, salvo el estado de la actividad cuando se gira la pantalla para que pueda recuperar todo lo anterior cuando se llame de nuevo a la actividad onCreate (). Referir este enlace

2. Si desea evitar el reinicio de la actividad, solo coloque las siguientes líneas en su archivo manifest.xml.

   

En la sección de actividad del manifest , agregue:

 android:configChanges="keyboardHidden|orientation" 

Después de un tiempo de prueba y error, encontré una solución que se adapta a mis necesidades en la mayoría de las situaciones. Aquí está el Código:

Configuración de manifiesto:

            

Actividad principal:

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

Y Fragmento de muestra:

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

Se puede encontrar en github .

Use el oyente de orientation para realizar diferentes tareas con diferente orientación.

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

Coloque este código a continuación en su Activity en Android Manifest .

 android:configChanges="orientation" 

Esto no reiniciará su actividad cuando cambie la orientación.

Corrige la orientación de la pantalla (horizontal o vertical) en AndroidManifest.xml

android:screenOrientation="portrait" o android:screenOrientation="landscape"

para esto, no se llama a su método onResume() .

Agregue esta línea a android: configChanges = “orientation | screenSize” en manifiesto

La gente dice que deberías usar

 android:configChanges="keyboardHidden|orientation" 

Pero la mejor y más profesional forma de manejar la rotación en Android es usar la clase Loader. No es una clase famosa (no sé por qué), pero es mucho mejor que AsyncTask. Para obtener más información, puede leer los tutoriales de Android encontrados en los cursos de Android de Udacity.

Por supuesto, como otra forma, puede almacenar los valores o las vistas con onSaveInstanceState y leerlos con onRestoreInstanceState. Depende de ti realmente.

Puede bloquear la orientación actual de la pantalla usando este código …

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