Pregunta

En mi aplicación de Android, cuando giro el dispositivo (deslizo el teclado hacia afuera), mi Activity se reinicia (onCreate se llama).Probablemente así es como se supone que debe ser, pero hago muchas configuraciones iniciales en el onCreate método, entonces necesito:

  1. Coloque toda la configuración inicial en otra función para que no se pierda por completo en la rotación del dispositivo o
  2. Hazlo así onCreate no se vuelve a llamar y el diseño simplemente se ajusta o
  3. Limite la aplicación solo a retrato para que onCreate no se llama.
¿Fue útil?

Solución

Usando la clase de aplicación

Dependiendo de lo que esté haciendo en su inicialización, podría considerar crear una nueva clase que se extienda Application y moviendo su código de inicialización a un anulado onCreate método 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 toda la aplicación, por lo que la actividad se reinicia con los cambios de orientación o visibilidad del teclado no la activará.

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 usando captadores y definidores.

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

<application
    android:name="com.you.yourapp.MyApplicationClass"

Reaccionar a los cambios de configuración [ACTUALIZAR:esto está en desuso desde API 13; ver la alternativa recomendada]

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

Comience agregando el android:configChanges nodo al nodo manifiesto de su actividad

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

o por Android 3.2 (API nivel 13) y más reciente:

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize"
      android:label="@string/app_name">

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

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

Otros consejos

Actualización para Android 3.2 y superior:

  

Precaución : a partir de Android 3.2 (nivel 13 de API), la " tamaño de 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 al cambio de orientación al desarrollar para el nivel 13 de API o superior (según lo declarado por los atributos minSdkVersion y targetSdkVersion), debe incluir el valor "screenSize" además del valor "orientation". Es decir, debe declarar android:configChanges="orientation|screenSize". Sin embargo, si su aplicación se dirige al nivel de API 12 o inferior, entonces su actividad siempre maneja este cambio de configuración por sí mismo (este cambio de configuración no reinicia su actividad, incluso cuando se ejecuta en un dispositivo Android 3.2 o superior).

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

Por ejemplo, si tengo alguna lógica que debería ejecutarse cuando el Activity se crea realmente, no en cada cambio de orientación, solo ejecuto esa lógica en el <=> solo si el <=> 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 si esta es la respuesta definitiva, pero funciona para mí.

lo que hice ...

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

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

Lo que describe es el comportamiento predeterminado. Debe detectar y manejar estos eventos usted mismo agregando:

android:configChanges

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

android:configChanges="orientation"

y para que el teclado se abra o cierre, usaría:

android:configChanges="keyboardHidden"

Si desea manejar ambos, puede 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.

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 la muestra de código anterior sugiera esto en el archivo de manifiesto:

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

que tiene el beneficio adicional de que siempre funciona.

La historia adicional es que omitir el keyboardHidden puede parecer lógico, pero causa fallas en el emulador (al menos para Android 2.1): al especificar solo orientation hará que el emulador llame tanto a OnCreate como a <=> a veces, y solo <=> otras veces.

No he visto la falla en un dispositivo, pero he oído que el emulador falla para otros. Vale la pena documentarlo.

También podría considerar usar 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 a través de 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 ha calculado en onCreate o desde entonces, mientras que también permite que Android vuelva a diseñar su Activity usando el archivo xml para la orientación ahora en uso.

Ver aquí o aquí .

Debe tenerse en cuenta que estos métodos ahora están en desuso (aunque aún más flexible que la orientación del manejo, cambie usted mismo como sugiere la mayoría de las soluciones anteriores) con la recomendación de que todos cambien a Fragments y en su lugar usen < code> setRetainInstance (true) en cada Fragment que desea conservar.

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

Los fragmentos generalmente se recrean al cambiar la configuración. Si no desea que esto suceda, use

setRetainInstance (true); en los constructores del Fragmento

Esto hará que se retengan fragmentos 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 de manifiesto y no agregó ningún método onConfigurationChanged en mi actividad.

Entonces, cada vez que el teclado se desliza hacia afuera o no sucede nada .

El método onCreate todavía se llama incluso cuando cambia la orientación de Android. Por lo tanto, mover todas las funciones pesadas a este método no te ayudará

Es muy simple, solo siga 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

Coloque el código a continuación dentro de su etiqueta < activity > en Manifest.xml :

android:configChanges="screenLayout|screenSize|orientation"
 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 le dice " no llame a onCreate () " ;?

Además, Los documentos de Google dicen que se debe evitar usar android: configChanges (excepto como último recurso) .... Pero luego, los métodos alternativos sugieren que todos DO usen android: configChanges .

Según mi experiencia, el emulador SIEMPRE llama a onCreate () al rotar.
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).

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 a realizar 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 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 use 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 usted 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
    }
}

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

La forma en que he encontrado para hacer esto es usar los eventos onRestoreInstanceState y onSaveInstanceState para guardar algo en el Bundle (incluso si usted 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á, realice la inicialización, si no, hágalo.

Aunque no es "la forma de Android" He obtenido muy buenos resultados manejando los cambios de orientación y simplemente reposicionando los widgets dentro de una vista para tener en cuenta la orientación alterada. 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, porque los widgets reposicionados son exactamente los mismos, simplemente movidos y / o redimensionados. No solo el estado del modelo, sino también el estado de vista, se pueden conservar de esta manera.

RelativeLayout a veces puede ser una buena opción para una vista que tiene que reorientarse de vez en cuando. Simplemente proporcione un conjunto de parámetros de diseño de retrato y un conjunto de parámetros de diseño de paisaje, con diferentes reglas de posicionamiento relativo en cada uno, para cada widget secundario. Luego, en su método onConfigurationChanged () , pasa el apropiado a una llamada setLayoutParams () en cada elemento secundario. Si algún control secundario en sí mismo necesita ser interno reorientado, simplemente llame a un método en ese elemento secundario para realizar la reorientación. Ese niño llama de manera similar a los métodos en cualquiera de sus controles secundarios que necesitan una reorientación interna, y así sucesivamente.

Cada vez que se gira la pantalla, la actividad abierta finaliza y se vuelve a llamar a onCreate ().

1. Puede hacer una cosa, salvo el estado de la actividad cuando se gira la pantalla para que pueda recuperar todas las cosas viejas cuando se vuelve a llamar a onCreate () de la actividad.     Consulte este 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"/>

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 roté la pantalla, no se llamó al método `onConfigurationChanged (Configuration newConfig).

Solución: también tuve que agregar " screenSize " incluso si el problema tuviera que ver con la orientación. Entonces, en el archivo AndroidManifest.xml, agregue esto:

android:configChanges="keyboardHidden|orientation|screenSize"

Luego implemente el método onConfigurationChanged (Configuration newConfig)

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

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

y usar

@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

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

android:configChanges="keyboardHidden|orientation"

Agregue esta línea en manifiesto: android:configChanges="orientation|screenSize"

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 que se encuentran 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.

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:

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

MainActivity:

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 la escucha de orientación para realizar diferentes tareas en diferentes orientaciones.

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

Ponga este código debajo en su Activity en Android Manifest .

android:configChanges="orientation"

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

Repara 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 () .

Uno de los mejores componentes de Android Architechure presentado por Google cumplirá con todos sus requisitos que es ViewModel.

Eso está diseñado para almacenar y administrar datos relacionados con la interfaz de usuario en el ciclo de vida, además de que permitirá que los datos sobrevivan a medida que la pantalla gira

class MyViewModel : ViewModel() {

Consulte esto: https://developer.android.com/topic/libraries / architecture / viewmodel

Puede bloquear la orientación actual de la pantalla con 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);
        }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top