Schritte:
Fragment
oder Activity
an.onRequestPermissionsResult()
anzeigenJava.lang.IllegalStateException
wird ausgelöst: Kann diese Aktion nach onSaveInstanceState
nicht ausführenDies ist nicht der Fall, wenn ich nach einiger Verzögerung einen Dialog zeige (mithilfe von postDelayed) . Laut http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html ) Bei Geräten nach Honeycomb KÖNNEN wir commit()
zwischen onPause()
und onStop()
ohne STAATLICHEN VERLUST oder AUSNAHME. Hier ist ein Link zu Beispielprojektquelle, Protokolldatei und aufgezeichnetem Thema . https://drive.google.com/folderview?id=0BwvvuYbQTUl6STVSZF9TX2VUeHM&usp=sharing
Außerdem habe ich ein Problem https://code.google.com/p/Android/issues/detail?id=190966 geöffnet, das jedoch als WorkingAsIntended markiert wurde und die Ausnahme vorschlagen. Aber das löst das Problem nicht. Ich kenne andere Wege, um es zu lösen, aber ist das nicht ein Android-Fehler?
UPDATE Status des Fehlers wird erneut "zugewiesen". Hoffe, dass es bald behoben wird . Meine temporäre Lösung ist
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// do your fragment transaction here
}
}, 200);
Der Fehler ist akzeptiert und wird behoben, jedoch stimme ich den PostDelayed- und Timer-Lösungen nicht zu. Am besten führen Sie dazu ein Status-Flag in der Activity ein, in dem Sie den Callback festlegen, und verwenden Sie onResume oder ähnliches. Zum Beispiel:
private boolean someFlag;
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// some code checking status
someFlag = true;
}
Und dann in onResume:
protected void onResume() {
if(someFlag == true) {
doSomething();
someFlag = false;
}
}
Ich denke auch, dass dies Android-Fehler ist. Ich kann nicht glauben, dass sie Ihr Problem markiert haben WorkingAsIntended . Die einzige Lösung fürs Erste ist, die Ausführung von Code in onRequestPermissionsResult()
zu verzögern, bis Android-Leute dies richtig beheben.
Dies ist meine Art, dieses Problem zu lösen, wenn jemand sich fragt, wie er die Ausführung verzögern kann:
@Override public void onRequestPermissionsResult (int requestCode, String [] -Berechtigungen, int [] grantResults) { if (requestCode == PERMISSION_CODE) { if (/ * ERLAUBNIS ERLAUBT/VERWEIGERT * /) { new Timer (). schedule (new TimerTask () { @Override public void run () { // EXECUTE-AKTIONEN (LIKE FRAGMENT TRANSACTION ETC.) } }, 0); __. } }
Dies verzögert die Ausführung im Wesentlichen, bis onRequestPermissionsResult()
abgeschlossen ist, sodass wir Java.lang.IllegalStateException
nicht erhalten. Das funktioniert in meiner App.
Da Sie eine DialogFragment
verwenden, sollten Sie ein Flag oder einen Zustand beibehalten und dann Ihr Dialogfeld in onPostResume
anzeigen. Sie sollten dies in onPostResume
und nicht in onResume
oder anderen Lebenszyklusmethoden tun.
Wie in documentation eindeutig angegeben, können Sie die Methode in einigen Fällen aufrufen, wenn Sie Transaktionen in anderen Aktivitätslebenszyklusmethoden als onPostResume
oder onResumeFragments
(für FragmentActivity) festlegen, bevor der Status der Aktivität vollständig wiederhergestellt wurde.
Wenn Sie also Ihren Dialog in PostResume anzeigen, ist alles in Ordnung.
versuche so etwas:
// ...
private Runnable mRunnable;
@Override
public void onResume() {
super.onResume();
if (mRunnable != null) {
mRunnable.run();
mRunnable = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (/* PERMISSION_DENIED */) {
mRunnable = /* new Runnable which show dialogFragment*/;
}
}
Dies ist ein Fehler in Android https://code.google.com/p/Android/issues/detail?id=190966&q=label%3AReportedBy-Developer&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
Daher sind im Moment Workarounds erforderlich. Sie können die Lösung von @ ldulcic verwenden. Oder Sie können die postDelay-Methode von Handler verwenden. Die zweite Option ist bevorzugt.
Ich bin damit umgegangen, von dem ich glaube, dass es viel deterministischer ist. Anstatt Timer zu verwenden, stelle ich das Ergebnis grundsätzlich in eine Warteschlange, bis Activity.onResumeFragments () (oder Sie können es in Activity.onResume () tun, wenn Sie keine Fragmente verwenden). Ich habe onResumeFragments () gemacht, weil ich das Ergebnis auch an das bestimmte Fragment weiterleite, das die Berechtigung angefordert hat. Ich muss also sicherstellen, dass die Fragmente bereit sind.
Hier ist das onRequestPermissionsResult ():
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
// This is super ugly, but google has a bug that they are calling this method BEFORE
// onResume... which screws up fragment lifecycle big time. So work around it. But also
// be robust enough to still work if/when they fix the bug.
if (mFragmentsResumed) {
routePermissionsResult(requestCode, permissions, grantResults);
} else {
mQueuedPermissionGrantResults = grantResults;
mQueuedPermissionRequestCode = requestCode;
mQueuedPermissions = permissions;
}
}
Dann ist hier onResumeFragments ():
@Override
protected void onResumeFragments() {
super.onResumeFragments();
mFragmentsResumed = true;
if (mQueuedPermissionGrantResults != null) {
routePermissionsResult(mQueuedPermissionRequestCode, mQueuedPermissions,
mQueuedPermissionGrantResults);
}
Der Vollständigkeit halber ist hier onPause () angegeben, wodurch das Flag mFragmentsResumed gelöscht wird:
@Override
protected void onPause() {
super.onPause();
mFragmentsResumed = false;
}
Ich habe das Flag mFragmentsResumed verwendet, weil ich nicht möchte, dass dieser Code nicht mehr funktioniert, wenn und wenn Google den Fehler behebt (eine Änderung der Reihenfolge der Lifecycle-Aufrufe würde dazu führen, dass der Code nicht funktioniert, wenn ich einfach die in der Warteschlange befindlichen Variablen in onRequestPermissionsResult festlegt, aber onResumeFragments war vorher genannt).
Ich habe es auch mit einem Handler gelöst, konnte aber die Verwendung eines Timers vermeiden, der seinen Looper auf MainLooper setzt. Es wird also ausgeführt, sobald die Ansicht gerendert wird:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// do your fragment transaction here
}
});
Wie in einem der Kommentare in issue erläutert, geschieht dies nur bei Verwendung der DialogFragment
der Support-Bibliothek (d. H. Android.support.v4.app.DialogFragment
). Sie können Ihren Code ändern, um die "native" DialogFragment
(Android.app.DialogFragment
) zu verwenden, und es wird gut funktionieren.
Ich weiß, dass die Verwendung der nativen Variable DialogFragment
in manchen Fällen nicht möglich ist. In diesem Fall können Sie dies jedoch, da Sie sich auf Laufzeitberechtigungen beziehen (eine Funktion, die nur in den neuesten Android-Versionen verfügbar ist). Ich hatte genau dieses Problem und konnte es so beheben.