2
votes

DialogFragment IllegalStateException lorsque l'écran s'éteint

Tout d'abord, j'ai lu des dizaines de questions SO et lu l'excellent article d'Alex Lockwood sur les problèmes IllegalStateException liés aux transactions de fragments: https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss. html - tl; dr J'ai fait mes devoirs

Mais ce que je n'ai trouvé nulle part, c'est le problème IllegalStateException lorsque l'écran s'éteint et nous essayons de valider une transaction fragmentée - affichez DialogFragment dans mon cas.

Ce qui se passe exactement dans mon application est de réagir à d'autres résultats d'activité et plus tard d'afficher un DialogFragment . Comme suggéré par de nombreux utilisateurs SO, je ne montre pas la boîte de dialogue de onActivityResult mais de onPostResume (j'ai aussi essayé avec onResumeFragments ) Le code simplifié ressemble à ceci

Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
       at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2053)
       at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2079)
       at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:678)
       at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:632)
       at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)

Je n'ai pas pu reproduire l'exception sur mon appareil (Mate 20 pro) ou sur l'émulateur mais je reçois des rapports d'erreur de utilisateurs de mon application (0,5% d'utilisateurs concernés)

Je suppose que mon application essaie d'afficher une boîte de dialogue après l'extinction de l'écran. La désactivation de l'écran est un événement arbitraire qui provoque l'appel de la méthode onSaveInstanceState et peut être appelée juste avant ma méthode onPostResume . Cependant, ce n'est que mon hypothèse !, peut-être qu'il y a une autre cause à l'exception

Quelqu'un a-t-il rencontré des problèmes similaires et a-t-il réussi à les gérer? Je sais que je peux utiliser commitAllowingStateLoss mais d'abord - la méthode show de DialogFragment ne permet pas de faire cela, je devrais afficher la boîte de dialogue manuellement en utilisant FragmentManager (je ne sais pas s'il y a des implications), deuxièmement, commitAllowingStateLoss est généralement une mauvaise chose à faire

J'ajoute un rapport de plantage bien que tout le monde l'a déjà vu quelque part :)

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    Timber.i("${this::class.java.simpleName} onActivityResult")
    activityResult = ActivityResult(this::class, requestCode, resultCode, data)
}

override fun onPostResume() {
    super.onPostResume()
    Timber.i("${this::class.java.simpleName} onPostResume")
    activityResult?.let { ActivityResultRepository.resultsSubject.onNext(it) }
}

override fun onResumeFragments() {
    super.onResumeFragments()
    Timber.i("${this::class.java.simpleName} onResumeFragments")
}


0 commentaires

3 Réponses :


0
votes

La classe d'activité a la méthode isFinishing () , lien vers la méthode . Vous pouvez facilement vérifier:

if (!this.isFinishing)
    loadingDialog.show()

Un exemple ci-dessus est l'ouverture d'un dialogue simple, mais vous pouvez l'utiliser avec DialogFragment.


0 commentaires

1
votes

Cela arrive souvent. L'activité n'est pas dans le bon état pour afficher une boîte de dialogue. Vous pouvez vous protéger avec ceci:

if (!isFinishing() && !isDestroyed()) {
    dialog.show();
}


0 commentaires

1
votes

J'ai accepté la réponse @MatPag car je me suis retrouvé avec une solution différente, alors je la poste, peut-être que cela aidera quelqu'un

Dans mon scénario, je me fiche de saveInstanceState - c'est parfait pour moi de afficher l'état initial d'une activité lorsque Android la recrée, donc je passe null à la méthode onCreate parent:

private fun DialogFragment.showAllowingStateLoss(manager: FragmentManager?, tag: String) {
    try {
        this.show(manager, tag)
    } catch (e: IllegalStateException) {
        // no-op
    }
}

Plus tard, en affichant une boîte de dialogue, j'attrape IllegalStateException qui peut être lancé, j'ai créé une méthode d'aide pour cela:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(null) 
}


0 commentaires