obteniendo la excepción "IllegalStateException: no se puede realizar esta acción después de onSaveInstanceState"

355

Tengo una aplicación de Android en vivo, y del mercado he recibido el siguiente seguimiento de la pila y no tengo idea de por qué está sucediendo, ya que no está sucediendo en el código de la aplicación, sino que es causado por algún u otro evento de la aplicación (supuesto)

No estoy usando Fragments, todavía hay una referencia de FragmentManager. Si algún cuerpo puede arrojar algo de luz sobre algunos hechos ocultos para evitar este tipo de problema:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)  
dcool
fuente
¿Ya encontraste una solución? Teniendo el mismo problema aquí: stackoverflow.com/questions/7575921/…
nhaarman
2
@phlebas No, no lo hiciste. La suya se refiere a diálogos, y esto no. La línea superior de la coincidencia de seguimiento de pila no es suficiente. El resto es muy diferente. Digo esto porque acabo de ver su problema y desafortunadamente no me ayuda.
themightyjon el
¿Utiliza un hilo o AsynTask en esa actividad?
José Castro
21
Discuto este error en mi blog ... deberías leerlo. :)
Alex Lockwood

Respuestas:

455

Este es el error más estúpido que he encontrado hasta ahora. Tenía una Fragmentaplicación que trabaja perfectamente para API <11 , y Force Closingel API> 11 .

Realmente no podía entender qué cambiaron dentro del Activityciclo de vida en la llamada saveInstance, pero aquí es cómo resolví esto:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

Simplemente no llamo .super()y todo funciona muy bien. Espero que esto te ahorre algo de tiempo.

EDITAR: después de un poco más de investigación, este es un error conocido en el paquete de soporte.

Si necesita guardar la instancia y agregarle algo outState Bundle, puede usar lo siguiente:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

EDIT2: esto también puede ocurrir si está intentando realizar una transacción después de que su Activityfondo haya desaparecido. Para evitar esto debes usarcommitAllowingStateLoss()

EDITAR3: Las soluciones anteriores solucionaron problemas en las primeras bibliotecas support.v4 de lo que puedo recordar. Pero si aún tiene problemas con esto, también DEBE leer el blog de @AlexLockwood : Fragment Transactions & Activity State Loss

Resumen de la publicación del blog (pero le recomiendo que lo lea):

  • NUNCA commit() transacciones posteriores onPause()a Honeycomb anteriores y onStop()posteriores a Honeycomb
  • Tenga cuidado al confirmar transacciones dentro de los Activitymétodos del ciclo de vida. Uso onCreate() , onResumeFragments()yonPostResume()
  • Evite realizar transacciones dentro de métodos de devolución de llamada asincrónicos
  • Úselo commitAllowingStateLoss()solo como último recurso
Ovidiu Latcu
fuente
97
Debería usar commitAllowingStateLoss () en lugar de commit ()
meh
77
Por lo tanto, no llamar a super en onSaveInstanceState detendrá que FragmentManager pueda guardar el estado de todos los fragmentos y restaurarlos. Eso podría causar problemas con la rotación. Además, acabo de intentar otra cosa sobre poner basura en el paquete y eso no hace ninguna diferencia para mí. No estoy seguro como lo haría - el insecto que se hace referencia en el paquete de apoyo es una NullPointerException, y no parece mucho a este IllegalStateException ...
themightyjon
56
@meh commitAllowingStateLoss()solo evita la excepción. No protege su aplicación de la pérdida accidental de estado. Ver esta publicación de blog .
Alex Lockwood
2
@AlexLockwood, así que de esa publicación de blog podemos aprender que deberíamos hacer todas nuestras llamadas de red dentro del fragmento (y mostrar un poco de progreso temporal ui si es necesario) y esa es la única forma en que podemos evitar obtener esta excepción cuando probablemente ocurra porque cometemos se llama después de una llamada a un método asincrónico.
meh
1
No entiendo el primer punto: "NUNCA confirme () transacciones después de ... onStop () en post-Honeycomb". ¿Qué sucede si necesito un botón para activar un fragmento para ser reemplazado por otro? ¿Debo poner un booleano que verifique si la actividad ha terminado en Stop, y si lo hace, llame a commitAllowingStateLoss en su lugar? Además, ¿qué sucede si tengo un fragmento dentro de un fragmento que necesito reemplazar al hacer clic en un botón?
Desarrollador de Android
76

Al buscar en el código fuente de Android las causas de este problema, el indicador mStateSaved en FragmentManagerImplclase (instancia disponible en Activity) tiene un valor verdadero. Se establece en verdadero cuando se guarda la pila posterior (saveAllState) en la llamada de Activity#onSaveInstanceState. Luego, las llamadas de ActivityThread no restablecen este indicador utilizando los métodos de restablecimiento disponibles desde FragmentManagerImpl#noteStateNotSaved()y dispatch().

A mi modo de ver, hay algunas soluciones disponibles, dependiendo de lo que esté haciendo y usando su aplicación:

Buenas maneras

Antes que nada: anunciaría el artículo de Alex Lockwood . Entonces, por lo que he hecho hasta ahora:

  1. Para fragmentos y actividades que no necesitan mantener ninguna información de estado, llame a commitAllowStateLoss . Tomado de la documentación:

    Permite que la confirmación se ejecute después de guardar el estado de una actividad. Esto es peligroso porque la confirmación puede perderse si la actividad necesita ser restaurada posteriormente de su estado, por lo que esto solo debe usarse en casos en los que está bien que el estado de la IU cambie inesperadamente en el usuario '. Supongo que esto está bien si el fragmento muestra información de solo lectura. O incluso si muestran información editable, use los métodos de devolución de llamada para retener la información editada.

  2. Justo después de que se confirme la transacción (que acaba de llamar commit()), realice una llamada a FragmentManager.executePendingTransactions().

Formas no recomendadas:

  1. Como Ovidiu Latcu mencionó anteriormente, no llame super.onSaveInstanceState(). Pero esto significa que perderá todo el estado de su actividad junto con el estado de los fragmentos.

  2. Anular onBackPressedy solo llamar allí finish(). Esto debería estar bien si su aplicación no utiliza Fragments API; como en super.onBackPressedhay una llamada a FragmentManager#popBackStackImmediate().

  3. Si está utilizando Fragments API y el estado de su actividad es importante / vital, entonces puede intentar llamar utilizando la API de reflexión FragmentManagerImpl#noteStateNotSaved(). Pero esto es un truco, o se podría decir que es una solución alternativa. No me gusta, pero en mi caso es bastante aceptable ya que tengo un código de una aplicación heredada que usa código obsoleto ( TabActivitye implícitamente LocalActivityManager).

A continuación se muestra el código que utiliza la reflexión:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    invokeFragmentManagerNoteStateNotSaved();
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeFragmentManagerNoteStateNotSaved() {
    /**
     * For post-Honeycomb devices
     */
    if (Build.VERSION.SDK_INT < 11) {
        return;
    }
    try {
        Class cls = getClass();
        do {
            cls = cls.getSuperclass();
        } while (!"Activity".equals(cls.getSimpleName()));
        Field fragmentMgrField = cls.getDeclaredField("mFragments");
        fragmentMgrField.setAccessible(true);

        Object fragmentMgr = fragmentMgrField.get(this);
        cls = fragmentMgr.getClass();

        Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {});
        noteStateNotSavedMethod.invoke(fragmentMgr, new Object[] {});
        Log.d("DLOutState", "Successful call for noteStateNotSaved!!!");
    } catch (Exception ex) {
        Log.e("DLOutState", "Exception on worka FM.noteStateNotSaved", ex);
    }
}

¡Salud!

gunar
fuente
Esto parece suceder también con ActionBarSherlock, bajo Gingerbread, por lo que el caso de verificar Build Id parece discutible ... :(
t0mm13b
Además, debe señalar: eso tampoco es adecuado para el uso de ABS :)
t0mm13b
@ t0mm13b: El código anterior representa mi proyecto, ya que no utiliza ni fragmentos ni soporte. FragmentActivity. Se ejecuta en android.app.Activity y dado que la inconsistencia que desencadena la Excepción es causada por FragmentManager (API nivel 11 hacia arriba), es por eso que la verificación ... Si crees que la fuente del mal es la misma para ti, siéntete libre para quitar el cheque. ABS es una historia diferente ya que se ejecuta sobre el paquete de compatibilidad y la implementación de soporte. FragmentActivity puede usar la misma implementación de FragmentManager y listo: el mismo problema.
Gunar
@ t0mm13b: para agregar más de 600 caracteres no es suficiente, primero debes investigar qué es lo que realmente te está causando esto. También debes darte cuenta de que lo anterior es un truco feo y no estoy asumiendo ninguna responsabilidad si funciona o no (para mí fue la mejor solución teniendo en cuenta las circunstancias). Si tiene que usarlo, verifique dos veces el código fuente de compatibilidad para nombres variables, ya que pueden diferir del paquete estándar. Espero que este problema se aborde en las próximas versiones del paquete de compatibilidad, pero desde la experiencia de Android, hay pocas posibilidades de que suceda ...
gunar
Uhhh ... Es exactamente el mismo problema que en este informe de error, que es el punto de la pregunta de este OP. Respaldo mi comentario: deberías haber incluido explícitamente un descargo de responsabilidad y decir que no está garantizado y también deberías haber declarado que no usaste fragmentos; de lo contrario, ¿por qué molestarse en publicar esa respuesta? :) Solo digo ...
t0mm13b
35

Dicha excepción ocurrirá si intenta realizar una transición de fragmento después de que onSaveInstanceState()se llame a su actividad de fragmento .

Una razón por la que esto puede suceder es si deja una AsyncTask(o Thread) en ejecución cuando se detiene una actividad.

Cualquier transición posterior a la onSaveInstanceState()llamada podría perderse si el sistema reclama la actividad para obtener recursos y la recrea más tarde.

FunkTheMonk
fuente
2
Hola Funk, tengo una pregunta aquí, ¿cómo se puede llamar a onBackPressed en esa actividad o fragmento, si esa actividad o fragmento se ha detenido? La excepción anterior parece generarse a partir de algún evento de IU (es decir, presionar la tecla ATRÁS), aunque no puedo encontrar la relación entre la Tarea Asíncrona y la tecla Atrás.
dcool
Como puede guardar las transiciones de fragmentos en el estado posterior, presionar el botón de retroceso puede provocar la inversión de la transición que guarda (por lo que los fragmentos antiguos vuelven). Se llama a onSaveInstanceState antes de que se destruya su actividad para restaurar los recursos en el sistema, no siempre después de que se llama a onStop. Lo siento, eso no estaba muy claro en mi respuesta.
FunkTheMonk
Funk, pero no estoy usando ningún Fragmento en mi aplicación. Podrían ser los fragmentos utilizados en el código nativo. antes pensé que estabas hablando de lo mismo.
dcool
1
Tenía una AsyncTask con una referencia a un fragmento. Problema resuelto después de eliminar la llamada super () de onSaveInstanceState y reemplazar la referencia de mi AsyncTask con un WeakReference <Fragment>.
Buffalo
2
@Buffalo Eso definitivamente no es una solución al problema. Siempre debes llamar super.onSaveInstanceState().
Alex Lockwood
27

Simplemente llame a super.onPostResume () antes de mostrar su fragmento o mueva su código en el método onPostResume () después de llamar a super.onPostResume (). Esto resuelve el problema!

MJ.Ahmadi
fuente
66
Llamar a onPostResume () asegura que se llame a onResumeFragments () y para mí esta es la solución ideal.
j2emanue
20

Esto también puede suceder cuando se invoca dismiss()un fragmento de diálogo después de que la pantalla se ha bloqueado \ en blanco y se ha guardado el estado de instancia del diálogo Actividad +. Para evitar esta llamada:

dismissAllowingStateLoss()

Literalmente, cada vez que descarto un cuadro de diálogo, de todos modos ya no me importa su estado, así que esto está bien, no estás perdiendo ningún estado.

Brian Dilley
fuente
2
Este fue mi problema exacto! Usted señor es brillante!
Tash Pemhiwa el
17

Solución corta y funcional:

Siga pasos simples:

Paso 1 : anule el estado onSaveInstanceState en el fragmento respectivo. Y elimine el súper método.

@Override
public void onSaveInstanceState(Bundle outState) {
};

Paso 2 : Use CommitAllowingStateLoss (); en lugar de commit (); mientras que las operaciones de fragmentos.

fragmentTransaction.commitAllowingStateLoss();
Basbous
fuente
1
Eliminar el súper método hizo el truco, ¿puedes explicar por qué? ¿Es seguro eliminar eso?
Bruce
77
no es seguro eliminar super (), ¡perderá otros datos conf después de eso!
deadfish
7

esto funcionó para mí ... descubrí esto por mi cuenta ... ¡espero que te ayude!

1) NO tiene un FragmentManager / FragmentTransaction global "estático".

2) onCreate, ¡SIEMPRE inicialice el FragmentManager nuevamente!

muestra a continuación: -

public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedInstanceState = savedInstanceState;
    setDefaultFragments();
}

protected void setDefaultFragments() {
    fragmentManager = getSupportFragmentManager();
    //check if on orientation change.. do not re-add fragments!
    if(mSavedInstanceState == null) {
        //instantiate the fragment manager

        fragmentTransaction = fragmentManager.beginTransaction();

        //the navigation fragments
        NavigationFragment navFrag = new NavigationFragment();
        ToolbarFragment toolFrag = new ToolbarFragment();

        fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
        fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
        fragmentTransaction.commitAllowingStateLoss();

        //add own fragment to the nav (abstract method)
        setOwnFragment();
    }
}
kurayami88
fuente
6

Siempre recibía esto cuando intentaba mostrar fragmentos en el método onActivityForResult (), por lo que el problema era el siguiente:

  1. Mi actividad está en pausa y detenida, lo que significa que ya se ha llamado a onSaveInstanceState () (para dispositivos anteriores y posteriores a Honeycomb).
  2. En caso de cualquier resultado, realicé una transacción para mostrar / ocultar el fragmento, lo que causa esta IllegalStateException.

Lo que hice es el siguiente:

  1. Valor agregado para determinar si se realizó la acción que quiero (por ejemplo, tomar una foto de camere - isPhotoTaken): puede ser un valor booleano o entero dependiendo de cuántas transacciones diferentes necesite.
  2. En el método anulado onResumeFragments (), verifiqué mi valor y luego realicé transacciones de fragmentos que necesitaba. En este caso, commit () no se realizó después de onSaveInstanceState, ya que el estado se devolvió en el método onResumeFragments ().
Formación
fuente
5

Resolví el problema con onconfigurationchanged. El truco es que de acuerdo con el ciclo de vida de la actividad de Android, cuando explícitamente llamaste una intención (intención de la cámara o cualquier otra); la actividad se detiene y se llama a onsavedInstance en ese caso. Al girar el dispositivo a una posición diferente a la que estaba activa durante la actividad; realizar operaciones con fragmentos como la confirmación de fragmentos causa una excepción de estado ilegal. Hay muchas quejas al respecto. Es algo sobre la gestión del ciclo de vida de la actividad de Android y las llamadas a métodos adecuados. Para resolverlo, hice esto: 1-Anule el método onsavedInstance de su actividad y determine la orientación actual de la pantalla (vertical u horizontal) y luego configure la orientación de la pantalla antes de que su actividad se detenga. de esa manera la actividad bloquea la rotación de la pantalla para su actividad en caso de que haya sido rotada por otra. 2-luego, anule el método de reanudación de actividad y configure su modo de orientación ahora como sensor de modo que después de que se llame al método guardado, se llame una vez más a la configuración para manejar la rotación correctamente.

Puede copiar / pegar este código en su actividad para tratarlo:

@Override
protected void onSaveInstanceState(Bundle outState) {       
    super.onSaveInstanceState(outState);

    Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
    int orientation =this.getDisplayOrientation();
    //Lock the screen orientation to the current display orientation : Landscape or Potrait
    this.setRequestedOrientation(orientation);
}

//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device 
public int getDisplayOrientation() {
    Display getOrient = getWindowManager().getDefaultDisplay();

    int orientation = getOrient.getOrientation();

    // Sometimes you may get undefined orientation Value is 0
    // simple logic solves the problem compare the screen
    // X,Y Co-ordinates and determine the Orientation in such cases
    if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        Configuration config = getResources().getConfiguration();
        orientation = config.orientation;

        if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        // if height and widht of screen are equal then
        // it is square orientation
            if (getOrient.getWidth() == getOrient.getHeight()) {
                orientation = Configuration.ORIENTATION_SQUARE;
            } else { //if widht is less than height than it is portrait
                if (getOrient.getWidth() < getOrient.getHeight()) {
                    orientation = Configuration.ORIENTATION_PORTRAIT;
                } else { // if it is not any of the above it will defineitly be landscape
                    orientation = Configuration.ORIENTATION_LANDSCAPE;
                }
            }
        }
    }
    return orientation; // return value 1 is portrait and 2 is Landscape Mode
}

@Override
public void onResume() {
    super.onResume();
    Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
} 
douggynix
fuente
4

Tuve el mismo problema, obteniendo IllegalStateException, pero reemplazar todas mis llamadas a commit () con commitAllowingStateLoss () no ayudó.

El culpable fue una llamada a DialogFragment.show ().

Lo rodeo con

try {
    dialog.show(transaction, "blah blah");
}
catch(IllegalStateException e) {
    return;
}

y eso lo hizo OK, no puedo mostrar el diálogo, pero en este caso estuvo bien.

Era el único lugar en mi aplicación donde primero llamé a FragmentManager.beginTransaction () pero nunca llamé a commit (), así que no lo encontré cuando busqué "commit ()".

Lo curioso es que el usuario nunca abandona la aplicación. En cambio, el asesino era un anuncio intersticial de AdMob que aparecía.

Roger CS Wernersson
fuente
3
Igual que aquí. He resuelto anular el método 'show (administrador de FragmentManager, etiqueta de cadena)', reemplazando 'commit' con 'commitAllowingStateLoss'; perder algo porque no puedo establecer dos atributos privados del Diálogo: mDismissed y mShownByMe. Pero parece funcionar cada vez :)
Francesco Ditrani
He creado una solución alternativa a DialogFragment, que puede evitar esta excepción: github.com/AndroidDeveloperLB/DialogShard
desarrollador de Android
4

Mi solución para ese problema fue

En fragmentos, agregue métodos:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ...
    guideMapFragment = (SupportMapFragment)a.getSupportFragmentManager().findFragmentById(R.id.guideMap);
    guideMap = guideMapFragment.getMap();
    ...
}

@Override
public void onDestroyView() {
    SherlockFragmentActivity a = getSherlockActivity();
    if (a != null && guideMapFragment != null) {
        try {
            Log.i(LOGTAG, "Removing map fragment");
            a.getSupportFragmentManager().beginTransaction().remove(guideMapFragment).commit();
            guideMapFragment = null;
        } catch(IllegalStateException e) {
            Log.i(LOGTAG, "IllegalStateException on exit");
        }
    }
    super.onDestroyView();
}

Puede ser malo, pero no pudo encontrar nada mejor.

mc.dev
fuente
Verdadero ... la captura de la excepción puede evitar el bloqueo de la aplicación, pero los problemas de comportamiento dejan esos fragmentos en la pantalla o no se agregan.
Marcos Vasconcelos
44
seguir desplazándose. la verdad está ahí afuera
anil
4

Tengo este problema, pero creo que este problema no está relacionado con commit y commitAllowStateLoss.

El siguiente mensaje de seguimiento y excepción de la pila es sobre commit ().

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

Pero esta excepción fue causada por onBackPressed ()

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(Unknown Source)
at android.support.v4.app.FragmentActivity.onBackPressed(Unknown Source)

Todos fueron causados ​​por checkStateLoss ()

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }

mStateSaved será verdadero después de onSaveInstanceState.

Este problema rara vez ocurre. Nunca he encontrado este problema. No puedo volver a ocurrir el problema.

Encontré el problema 25517

Podría haber ocurrido en las siguientes circunstancias

  1. La tecla de retroceso se llama después de onSaveInstanceState, pero antes de que se inicie la nueva actividad.

  2. use onStop () en el código

No estoy seguro de cuál es la raíz del problema. Así que usé una manera fea.

@Override
public void onBackPressed() {

    try{
        super.onBackPressed();
    }catch (IllegalStateException e){
        // can output some information here
        finish();
    }
}
oO_ox
fuente
Realmente no resolví el problema, pero este problema no está relacionado con commit y commitAllowStateLoss.
oO_ox
4

Tengo el mismo problema en mi aplicación. He resuelto este problema simplemente llamando a la super.onBackPressed();clase anterior y llamando commitAllowingStateLoss()a la clase actual con ese fragmento.

Peter
fuente
2
Gracias. Esta solución solucionó el problema de usar en commitAllowingStateLoss()lugar decommit()
Chintak Patel
Evite usar commitAllowingStateLoss () medium.com/@elye.project/…
swooby
3

Se llamará a onSaveInstance si un usuario gira la pantalla para que pueda cargar los recursos asociados con la nueva orientación.

Es posible que este usuario gire la pantalla seguido de presionar el botón Atrás (porque también es posible que este usuario haya perdido su teléfono mientras usa su aplicación)

dols
fuente
2
Si bien los cambios de configuración (como los cambios de orientación) pueden dar lugar a esta excepción, no son la causa raíz.
Alex Lockwood
2

Mismo problema mío y después de un día de análisis de todos los artículos, blog y stackoverflow, encontré una solución simple. No use salvadoInstanceState en absoluto, esta es la condición con una línea de código. En el código de fragmento:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
    .....
Tobia Caneschi
fuente
2

Esto sucede cada vez que intenta cargar un fragmento, pero la actividad ha cambiado su estado a onPause (). Esto sucede, por ejemplo, cuando intenta obtener datos y cargarlos en la actividad, pero cuando el usuario hace clic en algún botón y tiene movido a la siguiente actividad.

Puedes resolver esto de dos maneras

Puede usar transacción.commitAllowingStateLoss () en lugar de transacción.commit () para cargar el fragmento, pero puede terminar perdiendo la operación de confirmación que se realiza.

o

Asegúrese de que la actividad se reanude y no se detenga cuando cargue un fragmento. Cree un booleano y verifique si la actividad no va al estado onPause ().

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

luego, mientras carga el fragmento, verifique si hay actividad presente y cargue solo cuando la actividad esté en primer plano.

if(mIsResumed){
 //load the fragment
}
Sharath kumar
fuente
1

Gracias @gunar, pero creo que hay una mejor manera.

Según el documento:

 * If you are committing a single transaction that does not modify the
 * fragment back stack, strongly consider using
 * {@link FragmentTransaction#commitNow()} instead. This can help avoid
 * unwanted side effects when other code in your app has pending committed
 * transactions that expect different timing.
 *
 * @return Returns true if there were any pending transactions to be
 * executed.
 */
public abstract boolean executePendingTransactions();

Entonces use commitNowpara reemplazar:

fragmentTransaction.commit();
FragmentManager.executePendingTransactions()
JianxinLi
fuente
0

Bueno, después de probar todas las soluciones anteriores sin éxito (porque básicamente no tengo transacciones).

En mi caso, estaba usando AlertDialogs y ProgressDialog como fragmentos que, a veces, en la rotación, al solicitar el FragmentManager, el error aumenta.

Encontré una solución alternativa mezclando muchas publicaciones similares:

Es una solución de 3 pasos, todo hecho en su FragmentActivity (en este caso, se llama GenericActivity):

private static WeakReference<GenericActivity> activity = null; //To avoid bug for fragments: Step 1 of 3

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    //To avoid bug for fragments: Step 2 of 3
    activity = new WeakReference<GenericActivity>(this);
}

@Override
public FragmentManager getSupportFragmentManager(){
    //To avoid bug for fragments: Step 3 of 3
    if (this == activity.get()) {
        return super.getSupportFragmentManager();
    }
    return activity.get().getSupportFragmentManager();
}
Antilope
fuente
0

Cuando uso startactivity en un fragmento, obtendré esta excepción;

Cuando cambio para usar startactivityforresult, la excepción se ha ido :)

Entonces, la forma fácil de solucionarlo es usar la API startActivityForResult :)

Pregunta
fuente
0

Obtuve esta excepción cuando presioné el botón Atrás para cancelar el selector de intención en mi actividad de fragmento de mapa. Resolví esto reemplazando el código de onResume () (donde estaba inicializando el fragmento y confirmando la transacción) por onStart () y la aplicación está funcionando bien ahora. Espero eso ayude.

DCS
fuente
0

Esto se soluciona en Android 4.2 y también en la fuente de la biblioteca de soporte. [*]

Para obtener detalles sobre la causa (y las soluciones), consulte el informe de errores de Google: http://code.google.com/p/android/issues/detail?id=19917

Si está utilizando la biblioteca de soporte, no debería preocuparse por este error (por mucho tiempo) [*]. Sin embargo, si está utilizando la API directamente (es decir, no está utilizando el FragmentManager de la biblioteca de soporte) y apunta a una API por debajo de Android 4.2, deberá probar una de las soluciones alternativas.

[*] Al momento de escribir esto, Android SDK Manager todavía está distribuyendo una versión anterior que exhibe este error.

Editar Voy a agregar algunas aclaraciones aquí porque obviamente de alguna manera he confundido a quien rechazó esta respuesta.

Hay varias circunstancias diferentes (pero relacionadas) que pueden hacer que se produzca esta excepción . Mi respuesta anterior se refiere a la instancia específica discutida en la pregunta, es decir, un error en Android que posteriormente se ha solucionado. Si obtiene esta excepción por otra razón, es porque está agregando / eliminando fragmentos cuando no debería (después de que se hayan guardado los estados de fragmento). Si se encuentra en una situación así, quizás " Fragmentos anidados - IllegalStateException" No se puede realizar esta acción después de onSaveInstanceState " " puede serle útil.

Benjamin Dobell
fuente
0

Mi caso de uso: he usado un oyente en fragmentos para notificar a la actividad que algo sucedió. Hice un nuevo compromiso de fragmento en el método de devolución de llamada. Esto funciona perfectamente bien la primera vez. Pero en el cambio de orientación, la actividad se recrea con el estado de instancia guardado. En ese caso, el fragmento no se crea de nuevo implica que el fragmento tiene el oyente, que es la actividad destruida. De cualquier forma, el método de devolución de llamada se activará en la acción. Va a la actividad destruida que causa el problema. La solución es restablecer el oyente en fragmentos con la actividad en vivo actual. Esto resuelve el problema.

Ganesh Kanna
fuente
0

Lo que encontré es que si otra aplicación es del tipo de diálogo y permite enviar toques a la aplicación de fondo, casi cualquier aplicación de fondo se bloqueará con este error. Creo que debemos verificar cada vez que se realiza una transacción si la instancia se guardó o restauró.

Chris
fuente
0

En mi caso, con la misma excepción de error, puse el "onBackPressed ()" en un archivo ejecutable (puede usar cualquiera de sus vistas):

myView.post(new Runnable() {
                    @Override
                    public void run() {
                        onBackPressed()
                    }
                });

No entiendo por qué, ¡pero funciona!

Alecs
fuente
Publicar en una vista solo ejecutará Runnable después de que la vista se haya diseñado y dibujado correctamente en la pantalla; esto significa a menudo la propia actividad se ha reanudado plenamente, por lo tanto, no hay problemas
Mercato
0

Puede estar llamando a fragmentManager.popBackStackImmediate (); cuando la actividad está en pausa. La actividad no está terminada pero está en pausa y no está en primer plano. Debe verificar si la actividad está en pausa o no antes de popBackStackImmediate ().

Murat
fuente
0

Noté algo muy interesante. Tengo en mi aplicación la opción de abrir la galería del teléfono y el dispositivo pregunta qué aplicación usar, allí hago clic en el área gris fuera del cuadro de diálogo y veo este problema. Noté cómo mi actividad va de onPause, onSaveInstanceState a onResume, no sucede que visite onCreateView. Estoy haciendo transacciones en onResume. Entonces, lo que terminé haciendo es configurar una marca que se niega en Pausa, pero que es verdadera en Crear Vista. si el indicador es verdadero en Resume, entonces haga onCommit, de lo contrario commitAllowingStateLoss. Podría seguir y perder mucho tiempo, pero quería comprobar el ciclo de vida. Tengo un dispositivo que es sdkversion 23, y no tengo este problema, pero tengo otro que es 21, y ahí lo veo.

Juan mendez
fuente
-1

puedes usar FragmentActivity.onStart antes de popBackStackImmediate

Me gusta esto:

public void backStackFragment() {
    this.start();
    getFragmentManager().popBackStackImmediate();
}

public void start(){
    FragmentActivity a = getActivity();
    if(a instanceof DepositPlanPadActivity){
      ((DepositPlanPadActivity)a).onStart();
    }
    if(a instanceof SmallChangePlanPad){
            ((SmallChangePlanPad)a).onStart();
        }
        if(a instanceof UserCenterActivity){
            ((UserCenterActivity)a).onStart();
        }
    }

http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html

usuario3327339
fuente