"Ergebnis der Fehlerbereitstellung" - onActivityForResult

74

Ich habe eine LoginActivity(Benutzeranmeldung). Es ist im Grunde genommen ein eigenes ActivityThema, das wie ein Dialog thematisiert ist (um als Dialog zu erscheinen). Es erscheint über a SherlockFragmentActivity. Was ich möchte ist: Wenn es eine erfolgreiche Anmeldung gibt, sollten zwei vorhanden sein FragmentTransaction, um die Ansicht zu aktualisieren. Hier ist der Code:

Bei LoginActivityerfolgreicher Anmeldung

setResult(1, new Intent());

In SherlockFragmentActivity:

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

    if (resultCode == 1) {
        LoggedStatus = PrefActivity.getUserLoggedInStatus(this);
        FragmentTransaction t = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
        SherlockListFragment mFrag = new MasterFragment();
        t.replace(R.id.menu_frame, mFrag);
        t.commit();

        // Set up Main Screen
        FragmentTransaction t2 = MainFragmentActivity.this.getSupportFragmentManager().beginTransaction();
        SherlockListFragment mainFrag = new FeaturedFragment();
        t2.replace(R.id.main_frag, mainFrag);
        t2.commit();
    }
}

Es stürzt beim ersten Commit mit diesem LogCat ab:

E/AndroidRuntime(32072): Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
E/AndroidRuntime(32072):    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299)
E/AndroidRuntime(32072):    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310)
E/AndroidRuntime(32072):    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541)
E/AndroidRuntime(32072):    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525)
E/AndroidRuntime(32072):    at com.kickinglettuce.rate_this.MainFragmentActivity.onActivityResult(MainFragmentActivity.java:243)
E/AndroidRuntime(32072):    at android.app.Activity.dispatchActivityResult(Activity.java:5293)
E/AndroidRuntime(32072):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)
TheLettuceMaster
quelle
Wie haben Sie startActivityForResult ()
Rohit

Antworten:

293

Zuallererst sollten Sie meinen Blog-Beitrag lesen, um weitere Informationen zu erhalten (er spricht darüber, warum diese Ausnahme auftritt und was Sie tun können, um sie zu verhindern).

Anrufen commitAllowingStateLoss()ist eher ein Hack als ein Fix. Staatsverlust ist schlecht und sollte unter allen Umständen vermieden werden. Zum Zeitpunkt onActivityResult()des Aufrufs wurde der Status der Aktivität / des Fragments möglicherweise noch nicht wiederhergestellt. Daher gehen alle Transaktionen, die während dieser Zeit stattfinden, verloren. Dies ist ein sehr wichtiger Fehler, der behoben werden muss! (Beachten Sie, dass der Fehler nur auftritt, wenn Sie Activityzurückkommen, nachdem Sie vom System getötet wurden. Dies kann je nach Speicherplatz des Geräts manchmal selten sein. Diese Art von Fehler ist also nicht vorhanden sehr leicht zu fangen beim Testen).

Versuchen Sie onPostResume()stattdessen, Ihre Transaktionen zu verschieben (beachten Sie, dass onPostResume()immer nach onResume()und onResume()immer nach aufgerufen wird onActivityResult()):

private boolean mReturningWithResult = false;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mReturningWithResult = true;
}

@Override
protected void onPostResume() {
    super.onPostResume();
    if (mReturningWithResult) {
        // Commit your transactions here.
    }
    // Reset the boolean flag back to false for next time.
    mReturningWithResult = false;
}

Dies mag etwas seltsam erscheinen, aber dies ist erforderlich, um sicherzustellen, dass Ihre FragmentTransactions immer festgeschrieben werden, nachdem der Activityursprüngliche Status wiederhergestellt wurde ( onPostResume()wird garantiert aufgerufen, nachdem der ActivityStatus wiederhergestellt wurde). .

Alex Lockwood
quelle
4
In Fragmenten verwende ich onResume, wenn onPostResume nicht vorhanden ist. Ich habe das Problem nicht mehr gesehen, aber vielleicht möchten Sie dies kommentieren. PS. Vielen Dank für Ihre aufschlussreichen Beiträge!
Maragues
27
Ja, das Fragment#onResume()ist in Ordnung. Dies liegt daran, dass FragmentActivity#onPostResume()Aufrufe FragmentActivity#onResumeFragments(), welche Aufrufe FragmentManager#dispatchResume(), welche Fragment#onResume()für jedes der Fragmente der Aktivität aufrufen. Daher Fragment#onResume()wird nach aufgerufen, FragmentActivity#onPostResume()damit es kein Problem gibt (Sie können den [Quellcode] ( goo.gl/Lo1Z1T ) für die jeweilige Klasse überprüfen, um dies selbst zu überprüfen ... oder Sie können einfach nur mich: P. ). Und danke! Ich bin froh, dass du sie für aufschlussreich gehalten hast. :)
Alex Lockwood
2
@crazyhorse In diesem Fall ist es möglicherweise eine gute Idee, die asynchrone Aufgabe abzubrechen und / oder ein Flag zu setzen, um sicherzustellen, dass sie dismiss()nicht im Inneren aufgerufen wird AsyncTask#onPostExecute()(der Dialog wird automatisch von dem FragmentManagerfür den Fall geschlossen, dass die Aktivität im Hintergrund ausgeführt wird Sie müssen den Dialog also nicht selbst schließen, nachdem die Aktivität ohnehin beendet wurde.
Alex Lockwood
1
Wusste nichts davon onPostResume(). Das Problem wurde behoben (ich habe ein Dialogfragment erstellt, onResume()nachdem ein Systemdialog aus einer ausstehenden Absicht abgebrochen wurde, wodurch meine App abgestürzt ist).
EpicPandaForce
1
@ AlexLockwood danke für diesen Beitrag. In Ihrem Blog sagen Sie, dass Transaktionen nach Aktivität # onPostResume festgeschrieben werden sollten. Gleichzeitig sagen Sie jedoch, dass sie in Aktivität # onCreate (die noch vor onResume ausgeführt wird) festgeschrieben werden können. Ich bin mir sicher, dass ich etwas falsch verstanden habe. Können Sie das erklären?
nutella_eater
1

Dies ähnelt der Antwort von @Alex Lockwood, verwendet jedoch Folgendes Runnable:

private Runnable mOnActivityResultTask;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mOnActivityResultTask = new Runnable() {
        @Override
        public void run() {
            // Your code here
        }
    }
}

@Override
protected void onPostResume() {
    super.onPostResume();
    if (mOnActivityResultTask != null) {
        mOnActivityResultTask.run();
        mOnActivityResultTask = null;
    }
}

Wenn Sie Android 3.0 und höher mit Lambdas ausführen , verwenden Sie Folgendes :

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mOnActivityResultTask = () -> {
        // Your code here
    }
}
vovahost
quelle
Ich würde lieber mit runnable arbeiten, da Sie so die Logik nahe an den Ort schreiben können, an dem sie auftritt. In meinem Fall kommt es vom RX-Abonnenten.
Fabio
-2

Sie können ft.commitAllowingStateLoss()dieses Problem lösen.

Grund: Ihre ft.commit()Methode wurde nach umgeschaltet onSaveInstanceState.

muyiou
quelle
-2

Ihr Logcat sagt eindeutig: "Diese Aktion kann nach onSaveInstanceState nicht ausgeführt werden" - Sie Activitysind zu diesem Zeitpunkt bereits tot und konnten keine Ergebnisse zurückgeben.

Beweg dich einfach:

Intent in = new Intent();
setResult(1, in);

zu dem Ort in deinem, an Activitydem es noch lebt, und alles wird gut. und vergessen finish()Sie nicht Activity, das Ergebnis zu liefern.

lenik
quelle
Vielen Dank. finish()ist das Letzte, was ich tue. Ich hatte den Absichtscode direkt darüber. Ich habe ihn nach oben verschoben und den gleichen Fehler. Ich
füge
Noch ein Punkt zum letzten Kommentar. Ich sehe eigentlich keinen Toast. Aber wenn ich die App nach dem Absturz wieder betrete, bin ich angemeldet.
TheLettuceMaster
-2

In meinem Fall hatte ich aus folgenden Gründen die gleichen Probleme

public void onBackPressed() {
    super.onBackPressed();
    setIntents();

}


private void setIntents(){
    Intent searchConstaints=new Intent();
    searchConstaints.putExtra("min",20);
    searchConstaints.putExtra("max",80);
    setResult(101,searchConstaints);
    finish();
}

Gelöst durch Neuanordnen der Funktion Aufrufe in onBackPressed ()

public void onBackPressed() {

    setIntents();
    super.onBackPressed();

}
RAJESH KUMAR ARUMUGAM
quelle