DialogFragment IllegalStateException при выключении экрана - PullRequest
0 голосов
/ 08 января 2019

Прежде всего, я прочитал десятки SO вопросов и прочитал отличный пост Алекса Локвуда о IllegalStateException проблемах, связанных с транзакциями фрагментов: https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html - tl; dr Я сделал моя домашняя работа

Но то, что я нигде не нашел, это проблема IllegalStateException, когда экран гаснет и мы пытаемся зафиксировать транзакцию фрагмента - в моем случае покажите DialogFragment.

То, что происходит в моем приложении, - это реакция на результат другой активности, а затем отображение DialogFragment. Как предлагают многие пользователи SO, я не показываю диалог от onActivityResult, но от onPostResume (я пробовал также с onResumeFragments) Упрощенный код выглядит следующим образом

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")
}

Мне не удалось воспроизвести исключение на моем устройстве (Mate 20 pro) или на эмуляторе, но я получаю отчеты о сбоях от пользователей моего приложения (затронуто 0,5% пользователей)

Я предполагаю, что мое приложение пытается показать диалоговое окно после выключения экрана. Отключение экрана - это произвольное событие, которое вызывает метод onSaveInstanceState и может вызываться прямо перед моим onPostResume методом. Однако это только мое предположение !, может быть, есть и другая причина исключения

Кто-нибудь сталкивался с подобными проблемами и сумел их решить? Я знаю, что могу использовать commitAllowingStateLoss, но, во-первых, метод show из DialogFragment не позволяет этого сделать, придется показывать диалог вручную с помощью FragmentManager (не знаю, есть ли какие-либо последствия), во-вторых, commitAllowingStateLoss вообще плохо делать

Я добавляю отчет о сбое, хотя все уже видели его где-то:)

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)

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Это часто случается. Активность не в правильном состоянии, чтобы показать диалог. Вы можете защитить себя этим:

if (!isFinishing() && !isDestroyed()) {
    dialog.show();
}
0 голосов
/ 10 января 2019

Я принял ответ @MatPag, хотя в итоге я нашел другое решение, поэтому выкладываю его, может быть, оно кому-нибудь поможет

В моем сценарии меня не волнует saveInstanceState - мне совершенно нормально показывать начальное состояние действия, когда Android его воссоздает, поэтому я передаю null родительскому методу onCreate:

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

Позже, когда я показываю диалог, я ловлю исключение IllegalStateException, я создал вспомогательный метод для этого:

private fun DialogFragment.showAllowingStateLoss(manager: FragmentManager?, tag: String) {
    try {
        this.show(manager, tag)
    } catch (e: IllegalStateException) {
        // no-op
    }
}
0 голосов
/ 08 января 2019

В классе активности есть метод isFinishing(), ссылка на метод . Вы можете легко проверить:

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

Примером выше является открытие простого диалога, но вы можете использовать его с DialogFragment.

...