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

Проверка состояния сохранения до совершения FragmentTransaction

Иногда я вижу следующий стек для фиксации, который может произойти, когда пользователь не смотрит на активность (после сохранения состояния):

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

Глядя на источник Android, это имеет смысл:

private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        if (mNoTransactionsBecause != null) {
            throw new IllegalStateException(
                    "Can not perform this action inside of " + mNoTransactionsBecause);
        }
 }

Теперь, интересно, есть ли какой-либо способ (помимо хранения переменной класса в on (Save/Restore) InstanceState), чтобы проверить, будет ли фрагмент собираться в нежелательном состоянии, таким образом я могу хранить транзакцию для позже и совершите фиксацию в соответствующее время.

4b9b3361

Ответ 1

Поскольку вы не прикрепляли какой-либо примерный код, все, что я могу догадаться, это то, что вы используете "неправильный" метод при совершении транзакции.

поэтому вместо использования FragmentTransaction.commit() вы должны использовать FragmentTransaction.commitAllowingStateLoss().

Кроме того, есть сообщения и обходные пути об этой проблеме (или, скорее, изменение поведения API) в этом сообщении в блоге Google.

Ответ 2

Начиная с версии библиотеки поддержки 26.0.0 Beta 1 новый API доступен в классах FragmentManager и Fragment:

FragmentManager и Фрагмент имеют метод isStateSaved(), позволяющий запрашивать, разрешена ли транзакция без потери состояния. Это особенно полезно для проверки при обработке события onClick() перед выполнением любой транзакции.

Из документов android.support.v4.app.FragmentManager#isStateSaved():

Возвращает true, если состояние FragmentManager уже сохранено его хостом. Любые операции, которые изменяли бы сохраненное состояние, не должны выполняться, если этот метод возвращает true. Например, любой метод popBackStack(), например popBackStackImmediate() или любой FragmentTransaction, используя commit() из commitAllowingStateLoss() изменит состояние и приведет к ошибке.

Этот API будет поставляться с фреймворком android.app.FragmentManager, начиная с Android O.

Ответ 3

Неверно, Android Fragment не предоставляет проверку API, если это хорошо, чтобы совершить транзакцию.

Но мы можем добавить логическое поле в прикрепленную активность, помогая нам проверять. Пожалуйста, напишите следующий код.

public class GlobalBaseActivity extends FragmentActivity {

    private boolean mAllowCommit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mAllowCommit = true;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        mAllowCommit = false;
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onResumeFragments() {
        mAllowCommit = true;
        super.onResumeFragments();
    }

    public boolean allowFragmentCommit() {
        return mAllowCommit;
    } 

    public void callbackOnEvent() {
        if (allowFragmentCommit()){
            getFragmentManager().beginTransaction().add(new YourFragment(), TAG).commit();
        }
    }
}

Что касается выбора onResumeFragment() как индикатора транзакции, ref этот хороший блог. Это подробно объясняет известное исключение IllegalStateException.

Ответ 5

У меня тоже была эта проблема, я не мог найти решение где угодно. Я пробовал работать. Он работает так. Вместо этого сделайте транзакцию фрагмента из обработчика. Обработчик должен быть вызван с задержкой 2000 мс. Например. при вызове makeTransaction

void makeTransaction()
{
  handler.sendEmptyMessageDelayed(0,2000);
}

void actuallyMakeTransaction()
{
 // transaction code
}

Handler handler = new Handler()
{
void handleMessage(Message msg)
{
   actuallyMakeTransaction();
}
}

Он решил проблему для меня

Ответ 6

RuntimeExceptions (и IllegalStateException является одним из них) чаще всего означает, что ваш код неверен в том, как он пытался что-то добиться. Пытаться обработать такое исключение (например, поймав его) также неверно. Ваш код никогда не должен вести себя так, как Android будет генерировать на вас такое исключение.

Если вы используете Handlers и отправляете сообщение или отправляете сообщение, которое должно быть обработано в будущем, вам нужно очистить очередь перед выходом из возобновленного состояния. Также вы не можете просто запустить AsyncTask из Activity и совершить транзакцию в onPostExecute, потому что пользователь может вернуться из вашей Activity. Вам нужно отменить его и проверить, отменено ли оно.

Существует много таких примеров, и все они вызваны "временными" утечками памяти, например, мне нравится их называть.

В принципе, ваш код плох и без его предоставления, невозможно сказать, как это сделать.

Ответ 7

ft.commitAllowingStateLose() - ваш лучший выбор в этой ситуации. Однако, как указано, нет никакой гарантии, что ваше государство будет продолжаться.