Подтвердить что ты не робот

OnClick или onItemClick во время приостановленных результатов в "IllegalStateException: не удается выполнить это действие после onSaveInstanceState"

У меня есть TabActivity, который содержит 5x FragmentActivity. Некоторые из них содержат кнопки или списки, которые в своих onClick() или onItemClick() создают и нажимают новый фрагмент.

По большей части это прекрасно работает, но если вещи немного не реагируют, или тестер делает что-то глупое (нажмите и удерживайте кнопку или элемент списка, используйте другой палец для переключения вкладок, затем отпустите кнопка/список - 100% воспроизводимая), я получаю событие click после того, как действие приостановлено и сохранено. См. Фрагмент журнала:

10-30 17:05:16.258  3415  3415 D BKC DEBUG: More.onSaveInstanceState()
10-30 17:05:16.258  3415  3415 D BKC DEBUG: MoreFragment.onPause()
10-30 17:05:17.309  3415  3415 D BKC DEBUG: MoreFragment.onItemClick()

После прочтения этой статьи и различных вопросов StackOverflow о потере состояния фрагмента я не вижу хорошего ответа, как исправить это.

  • Использование commitAllowingStateLoss() (безоговорочно) - это обходной путь, который может скрыть настоящие ошибки.
  • Я не уверен, что отмена регистрации OnClickListener и OnItemClickListener в onSaveInstanceState будет на 100% предотвращать это, и это вроде PITA, чтобы сделать это для каждой кнопки в каждом фрагменте.
  • Кто-то предложил проверить соответствующий фрагмент isAdded(), но я могу подтвердить, что он не работает.
  • Я могу установить флаг в onSaveInstanceState() и onRestoreInstanceState() и проверить это в onClick(), но опять же, это просто kludge. EDIT: О, фрагмент не имеет onRestoreInstanceState(), но я могу обвести флаг в onResume() или что-то еще.

Есть ли правильное исправление для этого, которое мне не хватает, или я должен просто пойти с моим kludge по выбору?

4b9b3361

Ответ 1

Подумав об этом еще немного, я считаю, что commitAllowingStateLoss() на самом деле является правильным ответом для этого случая. Мы знаем, что мы находимся в обработчике onClick() или onItemClick(), поэтому, если потеря состояния может произойти, мы знаем это из-за этого отверстия, которое позволяет событиям щелчка через onSaveInstanceState().

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

Ответ 2

Я думаю, что более элегантным решением было бы просто проигнорировать событие click. Настройте очень простой логический флаг в BaseActivity, чтобы отслеживать, когда ваша активность приостановлена:

class BaseActivity extends BaseFragmentActivity {
    private boolean isPaused;

    @Override
    protected void onPause() {
        isPaused = true;
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        isPaused = false;
    }

    public boolean isPaused() {
        return isPaused;
    }
}

Всякий раз, когда вы получаете событие click, просто проверьте, приостановлена ​​ли ваша активность. Если это так, то очень безопасно игнорировать событие, так как нет смысла действовать на нем.

@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
    if (isPaused()) {
        //But... we're paused. Ignore.
        return;
    }

    //Act upon legitimate click events here
}

Ответ 3

Я могу подтвердить, что это проблема в библиотеке поддержки, а не в вашем коде. Лучшим обходным решением является (возможно) использование ответа, данного @Doge, который должен отслеживать приостановленное состояние самостоятельно.

Причина, по которой проблема с библиотекой поддержки заключается в том, что onClicks происходит после выпуска клика. Если вы используете несколько пальцев, вы можете выпустить другое событие щелчка где-нибудь еще (например, другую кнопку), которая изменяет фрагмент. Библиотека поддержки получает свое событие щелчка после изменения фрагмента и не проверяет, все ли находится на переднем плане. Это означает, что вы должны проверить это самостоятельно.

Это означает, что любой вызов setCurrentTab() или setCurrentTabByTag() должен включать проверку приостановленного состояния, если он хочет избежать этого сбоя. Пожалуйста, поправьте меня, если я ошибаюсь.

Ответ 4

Так как действие приостановлено, и действительно нет правильного действия, чтобы взять с выбранной вами вещи, возможно, самое лучшее действие - поймать и съесть исключение IllegalStateException. Пусть пользовательский интерфейс выполнит то, что он делал, и пусть FragmentTransaction упадет на пол.