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:
onCreate
no se llama de nuevo y el diseño simplemente se ajusta o 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 declararandroid: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:
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 } }
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 } }
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); }