579 Stimmen

IllegalStateException: Diese Aktion kann nicht nach onSaveInstanceState mit ViewPager durchgeführt werden

Ich erhalte Benutzerberichte von meiner App auf dem Markt, die die folgende Ausnahme liefern:

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.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
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:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
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.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
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:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
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:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)

Offenbar hat es etwas mit einem FragmentManager zu tun, den ich nicht verwende. Der Stacktrace zeigt keine meiner eigenen Klassen, daher habe ich keine Ahnung, wo diese Ausnahme auftritt und wie ich sie verhindern kann.

Für das Protokoll: Ich habe einen Tabhost, und in jedem Tab gibt es eine ActivityGroup, die zwischen den Activities wechselt.

5voto

Ivo Stoyanov Punkte 14531

Fragmenttransaktionen sollten nicht ausgeführt werden, nachdem Activity.onStop() ¡! Stellen Sie sicher, dass Sie keine Rückrufe haben, die eine Transaktion nach onStop() . Es ist besser, die Ursache zu beheben, anstatt zu versuchen, das Problem mit Ansätzen wie dem folgenden zu umgehen .commitAllowingStateLoss()

5voto

Lawrence Kesteloot Punkte 3972

Wenn Sie erben von FragmentActivity aufrufen, müssen Sie die Oberklasse in onActivityResult() :

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    ...
}

Wenn Sie dies nicht tun und versuchen, ein Fragment-Dialogfeld in dieser Methode anzuzeigen, erhalten Sie möglicherweise die OP's IllegalStateException . (Um ehrlich zu sein, verstehe ich nicht ganz por qué der Superaufruf behebt das Problem. onActivityResult() aufgerufen wird, bevor onResume() also sollte es immer noch nicht erlaubt sein, ein Fragment-Dialogfeld anzuzeigen).

4voto

Njuacha Hubert Punkte 348

Wie Sie in Ihrem Absturzbericht sehen können, ist die letzte Zeile, die die Ausnahme auslöst

checkStateLoss(FragmentManager.java:1109)

wenn Sie sich die Implementierung von checkStateLoss ansehen

private void checkStateLoss() {
    if (isStateSaved()) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
}

Eine einfache Lösung für mich besteht darin, die Methode des Fragment-Managers zu finden, die Sie in Ihrer Anwendung aufrufen, die schließlich zum Aufruf dieser Methode führt, und einfach zu prüfen, ob isStateSaved() falsch ist, bevor Sie diese Methode aufrufen. Bei mir war es die show()-Methode. Ich habe das so gemacht

if (!isStateSaved()) {
  myDialog.show(fragmentManager, Tag)
}

4voto

mojuba Punkte 11189

Die wahrscheinlich beste und einfachste Lösung, die ich in meinem Fall gefunden habe, war die Vermeidung des Ablegens des fraglichen Fragments vom Stapel als Reaktion auf das Aktivitätsergebnis. S onActivityResult() :

popMyFragmentAndMoveOn();

dazu:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    public void run() {
        popMyFragmentAndMoveOn();
    }
}

in meinem Fall geholfen.

3voto

Irshad Kumail Punkte 1133

Mit freundlicher Genehmigung: Lösung für IllegalStateException

Dieses Problem hat mich lange Zeit geärgert, aber zum Glück habe ich eine konkrete Lösung dafür gefunden. Eine ausführliche Erklärung dazu ist aquí .

Bisher haben wir verstanden, dass die IllegalStateException auftritt, wenn wir versuchen, ein Fragment zu übertragen, nachdem der Aktivitätsstatus verloren gegangen ist - also sollten wir die Transaktion einfach verzögern, bis der Status wiederhergestellt ist.

Deklarieren Sie zwei private boolesche Variablen

 public class MainActivity extends AppCompatActivity {

    //Boolean variable to mark if the transaction is safe
    private boolean isTransactionSafe;

    //Boolean variable to mark if there is any transaction pending
    private boolean isTransactionPending;

In onPostResume() und onPause setzen und löschen wir unsere boolesche Variable isTransactionSafe. Die Idee ist, eine Transaktion nur dann als sicher zu markieren, wenn die Aktivität im Vordergrund ist, so dass es keine Chance auf einen Statusverlust gibt.

/*
onPostResume is called only when the activity's state is completely restored. In this we will
set our boolean variable to true. Indicating that transaction is safe now
 */
public void onPostResume(){
    super.onPostResume();
    isTransactionSafe=true;
}
/*
onPause is called just before the activity moves to background and also before onSaveInstanceState. In this
we will mark the transaction as unsafe
 */

public void onPause(){
    super.onPause();
    isTransactionSafe=false;

}

private void commitFragment(){
    if(isTransactionSafe) {
        MyFragment myFragment = new MyFragment();
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.frame, myFragment);
        fragmentTransaction.commit();
    }
}

-Was wir bisher getan haben, schützt vor IllegalStateException, aber unsere Transaktionen gehen verloren, wenn sie durchgeführt werden, nachdem die Aktivität in den Hintergrund wechselt, ähnlich wie bei commitAllowStateloss(). Um dabei zu helfen, haben wir die boolesche Variable isTransactionPending

public void onPostResume(){
   super.onPostResume();
   isTransactionSafe=true;
/* Here after the activity is restored we check if there is any transaction pending from
the last restoration
*/
   if (isTransactionPending) {
      commitFragment();
   }
}

private void commitFragment(){

 if(isTransactionSafe) {
     MyFragment myFragment = new MyFragment();
     FragmentManager fragmentManager = getFragmentManager();
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
     fragmentTransaction.add(R.id.frame, myFragment);
     fragmentTransaction.commit();
     isTransactionPending=false;
 }else {
     /*
     If any transaction is not done because the activity is in background. We set the
     isTransactionPending variable to true so that we can pick this up when we come back to
foreground
     */
     isTransactionPending=true;
 }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X