webentwicklung-frage-antwort-db.com.de

Das Aufrufen von show () von DialogFragment innerhalb von onRequestPermissionsResult () verursacht IllegalStateException in Marshmallow

Schritte:

  1. Fordern Sie eine Genehmigung von Fragment oder Activity an.
  2. Ein DialogFragment aus onRequestPermissionsResult() anzeigen
  3. Java.lang.IllegalStateException wird ausgelöst: Kann diese Aktion nach onSaveInstanceState nicht ausführen

Dies 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);
35
android_dev

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;
    }
}
24
Kenneth

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.

6
ldulcic

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.

4
CanC

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*/;
   }
}
4
Scott Key

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

2
pdub

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
    }
});
0
Rubén Viguera

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.

0
Franco