rotacion - Actividad reinicio en rotación Android
manejando la rotación de pantalla en android studio (30)
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 "no llamar a onCreate()
"?
Además, los documentos de Google dicen que se debe evitar el uso de android:configChanges
(excepto como último recurso) ... Pero luego, los métodos alternativos que sugieren todos usan el android:configChanges
.
Ha sido mi experiencia que el emulador SIEMPRE llama onCreate()
en la rotación.
Pero los dispositivos 1-2 en los que ejecuto el mismo código ... no lo hacen. (No estoy seguro de por qué habría alguna diferencia).
En mi aplicación de Android, cuando giro el dispositivo ( onCreate
el teclado), se reinicia mi Activity
(se llama onCreate
). Ahora, probablemente es así como se supone que debe ser, pero hago mucha configuración inicial en el método onCreate
, así que necesito:
- Coloque toda la configuración inicial en otra función para que no se pierda todo en la rotación del dispositivo o
- Asegúrese de que
onCreate
no se vuelva a llamar y el diseño simplemente se ajusta o - Limite la aplicación a solo retrato para que no se llame a
onCreate
.
Añade esta línea a tu 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);
}
Acabo de descubrir esta historia
Para mantener viva la Actividad a través de un cambio de orientación, y manejarla a través de onConfigurationChanged
, la documentación y el ejemplo de código anterior sugieren esto en el archivo Manifest:
android:configChanges="keyboardHidden|orientation"
Que tiene el beneficio extra de que siempre funciona.
La experiencia adicional es que omitir el keyboardHidden
Oculto 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
, y solo a OnCreate
otras veces.
No he visto el fallo en un dispositivo, pero he oído que el emulador falla para otros. Así que vale la pena documentar.
Actualización para Android 3.2 y superior:
Precaución : A partir de Android 3.2 (nivel de API 13), el "tamaño de la pantalla" también cambia cuando el dispositivo cambia entre orientación vertical y horizontal. Por lo tanto, si desea evitar reinicios en tiempo de ejecución debido a un cambio de orientación al desarrollar 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 apunta al nivel de API 12 o inferior, entonces su actividad siempre maneja este cambio de configuración (este cambio de configuración no reinicia su actividad, incluso cuando se ejecuta en un dispositivo Android 3.2 o superior).
Agregue esta línea android: configChanges = "orientación | tamaño de pantalla" en el manifiesto
Aunque no es "a la manera de Android", he obtenido muy buenos resultados al manejar los cambios de orientación y simplemente reposicionando los widgets dentro de una vista para tener en cuenta la orientación modificada. Esto es más rápido que cualquier otro enfoque, ya que sus vistas no tienen que guardarse ni restaurarse. También proporciona una experiencia más fluida para el usuario, ya que los widgets reposicionados son exactamente los mismos widgets, solo se han movido y / o han cambiado de tamaño. No solo el estado del modelo, sino también el estado de la vista, se pueden conservar de esta manera.
RelativeLayout
veces puede ser una buena opción para una vista que debe reorientarse de vez en cuando. Solo proporciona un conjunto de parámetros de diseño vertical y un conjunto de parámetros de diseño paisajístico, con diferentes reglas de posicionamiento relativo en cada uno, para cada widget secundario. Luego, en tu método onConfigurationChanged()
, pasas el apropiado a una llamada a setLayoutParams()
en cada hijo. Si cualquier control secundario necesita ser reorientado internamente , simplemente llame a un método para que realice la reorientación. De manera similar, ese niño llama a los métodos de cualquiera de sus controles secundarios que necesitan reorientación interna, y así sucesivamente.
Cada vez que se gira la pantalla, se finaliza la actividad abierta y se vuelve a llamar a onCreate ().
1. Puede hacer una cosa, guardar el estado de actividad cuando se gira la pantalla, de modo que, puede recuperar todas las cosas antiguas cuando se vuelve a llamar a onCreate () de la actividad. Consulte this enlace
2. Si desea evitar el reinicio de la actividad, simplemente coloque las siguientes líneas en su archivo manifest.xml.
<activity android:name=".Youractivity"
android:configChanges="orientation|screenSize"/>
Coloque el código debajo de su etiqueta <activity>
en Manifest.xml
:
android:configChanges="screenLayout|screenSize|orientation"
Corrija 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()
.
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 del manifiesto:
<?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>
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 .
El enfoque es útil pero está incompleto cuando se usan Fragmentos.
Los fragmentos generalmente se recrean en el cambio de configuración. Si no desea que esto suceda, use
setRetainInstance(true);
en el (los) constructor (es) del Fragmento
Esto hará que los fragmentos se retengan durante el cambio de configuración.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)
En la sección de actividades del manifest
, agregue:
android:configChanges="keyboardHidden|orientation"
En lugar de intentar evitar que el onCreate()
se dispare por completo, intente verificar que el Bundle
savedInstanceState
se transfiera al evento para ver si es nulo o no.
Por ejemplo, si tengo alguna lógica que debería ejecutarse cuando se crea realmente la Activity
, no en cada cambio de orientación, solo ejecuto esa lógica en onCreate()
solo si el savedInstanceState
es nulo.
De lo contrario, todavía quiero que el diseño se vuelva a dibujar 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í.
Es muy sencillo solo haz los siguientes pasos:
<activity
android:name=".Test"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" >
</activity>
Esto funciona para mí:
Nota: la orientación depende de su requerimiento.
Hay varias formas de hacerlo:
Guardar estado de actividad
Puede guardar el estado de la actividad en 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);
}
y luego usar 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
}
}
Maneja los cambios de orientación por ti 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 versiones posteriores:
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
}
}
Restringir rotación
También puede limitar su actividad al modo retrato o paisaje para evitar la rotación.
Agregue esto a la etiqueta de actividad en su archivo de manifiesto:
android:screenOrientation="portrait"
O implementa esto programáticamente en tu actividad:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
La forma en que he encontrado esto es usar los onRestoreInstanceState
y onSaveInstanceState
para guardar algo en el Bundle
(incluso si no necesita guardar ninguna variable, simplemente coloque 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, si no, entonces hágalo.
La gente dice que debes 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 que se encuentran en los cursos de Android de Udacity.
Por supuesto, de otra manera, puede almacenar los valores o las vistas con onSaveInstanceState y leerlos con onRestoreInstanceState Depende de usted realmente.
Lo que usted describe es el comportamiento predeterminado. Tienes que detectar y manejar estos eventos por ti mismo agregando:
android:configChanges
a su manifiesto y luego los cambios que desea manejar. Entonces para la orientación, usarías:
android:configChanges="orientation"
y para el teclado que se está abriendo o cerrando usaría:
android:configChanges="keyboardHidden"
Si desea manejar ambos, puede simplemente separarlos con el comando de tubería 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.
Los cambios que se harán en el manifiesto de Android son:
android:configChanges="keyboardHidden|orientation"
Las adiciones que se hará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();
}
}
Pon este código debajo de tu Activity
en Android Manifest
.
android:configChanges="orientation"
Esto no reiniciará tu actividad cuando cambies de orientación.
Se onCreate
método onCreate
incluso cuando cambias la orientation
de Android. Así que mover toda la funcionalidad pesada a este método no te ayudará.
Simplemente añadí
android:configChanges="keyboard|keyboardHidden|orientation"
en el archivo de manifiesto y no agregó ningún método onConfigurationChanged
en mi actividad.
Así que cada vez que el teclado se desliza hacia fuera o en nada sucede .
También podría considerar el uso de la forma de la plataforma Android de persistir los datos en los cambios de orientación: onRetainNonConfigurationInstance()
y getLastNonConfigurationInstance()
.
Esto le permite conservar los datos en los cambios de configuración, como la información que puede haber obtenido de una búsqueda del servidor o algo más que se haya computado en onCreate
o desde entonces, mientras que también permite que Android vuelva a diseñar su Activity
utilizando el archivo xml para la orientación actual. en uso.
Debe tenerse en cuenta que estos métodos ahora están en desuso (aunque aún son más flexibles que la orientación por sí mismos, cambie como lo sugieren la mayoría de las soluciones anteriores) con la recomendación de que todos cambien a Fragments
y utilicen setRetainInstance(true)
en cada Fragment
que desee conservar .
Utilice la escucha de orientation
para realizar diferentes tareas en orientación diferente.
@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);
}
}
lo que hice...
En el manifiesto, a la sección de actividad, se añade:
android:configChanges="keyboardHidden|orientation"
En el código de 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();
}
necesita usar el método onSavedInstanceState para almacenar todo el valor para que su parámetro sea 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 los objetos que manejará las rotaciones de la pantalla
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, el método `onConfigurationChanged (Configuration newConfig) no fue llamado.
Solución: También tuve que agregar "tamaño de pantalla" incluso si el problema tenía que ver con la orientación. Entonces, en el archivo AndroidManifest.xml, agrega esto:
android:configChanges="keyboardHidden|orientation|screenSize"
Luego implemente el método onConfigurationChanged(Configuration newConfig)
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 aplicación solo se llama cuando se crea la aplicación completa, por lo que la Actividad se reinicia en la orientación o los cambios en la visibilidad del teclado no lo activarán.
Es una buena práctica exponer la instancia de esta clase como un singleton y exponer las variables de la aplicación que está inicializando utilizando captadores y definidores.
NOTA: Deberá especificar el nombre de su nueva clase de aplicación en el manifiesto para que se registre y se use:
<application
android:name="com.you.yourapp.MyApplicationClass"
Reaccionando a los cambios de configuración [ACTUALIZACIÓN: esto está en desuso desde la API 13; ver la alternativa recomendada ]
Como una alternativa adicional, puede hacer que su aplicación escuche eventos que podrían causar un reinicio, como cambios de orientación y visibilidad del teclado, y manejarlos dentro de su Actividad.
Comience agregando el nodo android:configChanges
nodo manifiesto de su actividad
android:configChanges="keyboardHidden|orientation"
o para Android 3.2 (API nivel 13) y más reciente :
android:configChanges="keyboardHidden|orientation|screenSize"
Luego, dentro de la Actividad, anule el método onConfigurationChanged
y llame a setContentView
para forzar que el diseño de la GUI se vuelva a realizar en la nueva orientación.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myLayout);
}
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);
}
Puedes usar el objeto ViewModel en tu actividad.
Los objetos de ViewModel se retienen automáticamente durante los cambios de configuración, de modo que los datos que contienen están inmediatamente disponibles para la siguiente actividad o instancia de fragmento. Lee mas:
https://developer.android.com/topic/libraries/architecture/viewmodel