java.lang.IllegalStateException: невозможно выполнить это действие после onSaveInstanceState с DialogFragment

У меня возникла проблема с DialogFragment/getSupportFragmentManager/Android версии 4.x.

01-10 19:46:48.228: E/AndroidRuntime(9879): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1314)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1325)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:532)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.showDialog(TermsAndConditions.java:256)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.handleMessage(TermsAndConditions.java:62)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions$IncomingHandler.handleMessage(TermsAndConditions.java:53)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.os.Looper.loop(Looper.java:137)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at android.app.ActivityThread.main(ActivityThread.java:4441)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at java.lang.reflect.Method.invokeNative(Native Method)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at java.lang.reflect.Method.invoke(Method.java:511)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at dalvik.system.NativeStart.main(Native Method)

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

Код хорошо работает на более старых версиях (до 4.x).

Может ли кто-нибудь направить меня в правильном направлении.

public class TermsAndConditions extends SherlockFragmentActivity implements LoaderManager.LoaderCallbacks<JSONObject>{
    static final String TAG = "TermsAndConditions";
    private static int titleResource;
    private static int messageResource;

    private IncomingHandler handler = null;
    private static final int SHOW_NETWORK_DIALOG = 3;

    static class IncomingHandler extends Handler {
        private final WeakReference<TermsAndConditions> mTarget; 

        IncomingHandler(TermsAndConditions target) {
            mTarget = new WeakReference<TermsAndConditions>(target);
        }

        @Override
        public void handleMessage(Message msg) {
            TermsAndConditions target = mTarget.get();
            if (target != null) {
                target.handleMessage(msg);
            }
        }
    }
    public void handleMessage(Message msg) {
        switch (msg.what)  {
            case SHOW_NETWORK_DIALOG:
                titleResource = R.string.msg_alert_no_network_title;
                messageResource = R.string.msg_alert_no_network_message;
                showDialog();
                break;
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.web_view);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportLoaderManager().initLoader(0, null, this);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    private void loadViewData() {
        //Logic to load content.
    }

    @Override
    public Loader<JSONObject> onCreateLoader(int arg0, Bundle arg1) {
        if (handler == null){
            handler = new IncomingHandler(TermsAndConditions.this);
        }
        return new JsonLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<JSONObject> arg0, JSONObject jsonData) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    @Override
    public void onLoaderReset(Loader<JSONObject> arg0) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    public static class JsonLoader extends AsyncTaskLoader<JSONObject> {
        public JsonLoader(Context context) {
            super(context);
        }

        @Override 
        protected void onStartLoading() {
            if (jsonDataObject != null) {
                deliverResult(jsonDataObject);
            }
            if (takeContentChanged() || jsonDataObject == null) {
                forceLoad();
            }
        }

        @Override
        public JSONObject loadInBackground() {
            try {
                return response.getJSONObject("result");
            } catch (JSONException e) {
                return null;
            } catch (Throwable e) {
                return null;
            }
        }

        @Override 
        public void deliverResult(JSONObject newJsonData) {
            if (isReset()) {
                if (jsonDataObject != null) {
                    onReleaseResources(jsonDataObject);
                }
            }
            JSONObject oldData = jsonDataObject;
            jsonDataObject = newJsonData;
            if (isStarted()) {
                super.deliverResult(jsonDataObject);
            }
            if (oldData != null) {
                onReleaseResources(oldData);
            }
        }

        @Override 
        protected void onStopLoading() {
            cancelLoad();
        }

        @Override public void onCanceled(JSONObject jsonData) {
            super.onCanceled(jsonData);
            onReleaseResources(jsonData);
        }

        @Override protected void onReset() {
            super.onReset();
            onStopLoading();
            if (jsonDataObject != null) {
                onReleaseResources(jsonDataObject);
                jsonDataObject = null;
            }
        }

        protected void onReleaseResources(JSONObject jsonData) {
            jsonData = null;
        }
    }
    public static class MyAlertDialogFragment extends DialogFragment {
        public static MyAlertDialogFragment newInstance(int title) {
            MyAlertDialogFragment frag = new MyAlertDialogFragment();
            Bundle args = new Bundle();
            args.putInt("title", title);
            frag.setArguments(args);
            return frag;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            int title = getArguments().getInt("title");
            return new AlertDialog.Builder(getActivity())
                    .setTitle(title)
                    .setMessage(messageResource)
                    .setPositiveButton(R.string.alert_dialog_ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {

                            }
                        }
                    )
                    .create();
        }
    }
    public void showDialog() {
        DialogFragment newFragment = MyAlertDialogFragment.newInstance(titleResource);
        newFragment.show(getSupportFragmentManager(), "my_dialog");
    }
}



Ответы (10)


Вот ответ в другой теме:

Действия в onActivityResult и Error Не удается выполнить это действие после onSaveInstanceState

также здесь:

Обновление моего фрагмента не работает так, как я думал

Это пример решения этой проблемы:

DialogFragment loadingDialog = createDialog();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                    transaction.add(loadingDialog, "loading");
                    transaction.commitAllowingStateLoss();  
person Khaled Annajar    schedule 05.03.2013
comment
Это не решает мою проблему - при использовании .commitAllowingStateLoss() ошибки нет, но диалог вообще не отображается. Нет ли другого способа, как это исправить? - person Micer; 02.07.2013
comment
У меня тоже такая же проблема, и это не решает ее. Фактически, это решение приводит к принудительному закрытию немедленно, еще до того, как DialogFragment будет показан. - person Karl Giesing; 05.08.2013
comment
Вы пытались позвонить getSupportFragmentManager().executePendingTransactions();. Я называю это после transaction.commitAllowingStateLoss(); - person ban-geoengineering; 25.05.2017

У меня такая же проблема, и я изменил код, как показано ниже.

newFragment.show(transactionFragment, "dialog");

to:

transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();

завершенный код хорошо работает для меня, как показано ниже, надеюсь, что поможет

FragmentTransaction transactionFragment = getActivity().getSupportFragmentManager().beginTransaction();
    DialogPageListFragment newFragment = new DialogPageListFragment();
    transactionFragment.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    newFragment.setArguments(extras);
    transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();
person Tran Khanh Tung    schedule 26.11.2014
comment
Вообще без вызова шоу? Разве это не портит работу внутреннего кода DialogFragment? - person android developer; 06.05.2015
comment
Делая это, getDialog() возвращает null внутри фрагмента диалога. :( - person Narendra Singh; 07.05.2020

Вероятно, обработчик, отвечающий на HandleMessage, связан с уничтоженной активностью.

то есть: если вы повернете экран, старая уничтоженная активность обработает сообщение, затем вы вызовете showDialog, и будет выбрано исключение:

Вы создаете диалог после того, как старая уничтоженная активность вызвала его onSaveInstanceState.

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


Если вы не вращаетесь, установите флаг onSaveInstance, например «сохранение», и отключите его в onRestoreInstance. В вашем методе handleMessage, если флаг «сохранение» включен, не показывайте диалоговое окно, просто включите другой флаг, указывающий, что диалоговое окно должно быть создано в onResume. Затем в методе onResume проверьте, следует ли в середине этого процесса создать диалоговое окно, если да, покажите его в методе onResume.

person noni    schedule 10.01.2013
comment
Моя деятельность только в одном направлении. - person Yogesh; 11.01.2013
comment
Попробуйте второй абзац, поставьте флаг, чтобы знать, когда вы Activity сохраняете свой экземпляр, и покажите диалог внутри метода onResume (он запускается после onRestoreInstanceState) - person noni; 11.01.2013
comment
После всех проб и ошибок единственное решение, которое сработало для меня, переопределяя метод show в расширенном классе фрагментов диалога. code @Override public void show (FragmentManager fm, тег String) { try { super.show (fm, тег); } catch (Throwable e) { //Utils.Log(TAG, e.getMessage()); } } - person Yogesh; 13.01.2013

fragmentView.post(() -> {
    FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
    YourDialog yourDialog = YourDialog.newInstance();
    yourDialog.show(ft, "text_data");
});

Целью метода post() в этом случае является ожидание завершения onResume() Activity или Fragment. Это работает, если вы хотите показать DialogFragment из Fragment., например. когда вы хотите показать свой диалог после закрытия системного диалога.

person Maksim    schedule 13.10.2016
comment
Мой код завернут в getView().post(), но я все еще вижу сбои в Crashlytics. - person RustamG; 17.01.2019

Я столкнулся с той же проблемой при задержке публикации Runnables handler.postDelayed(Runnable runnable, long delay).

Я решил проблему следующим образом:

  1. В onSaveInstanceState я отменяю отложенные задачи
  2. В onRestoreInstanceState я воссоздаю задачу, если были отложенные задачи, когда активность была уничтожена
person user2832184    schedule 17.12.2013
comment
Звучит как хороший трюк, но как долго должна быть задержка в handler.postDelay()? 100 мс достаточно - person Malachiasz; 20.02.2014
comment
не могли бы вы вставить пример кода, как вы воссоздаете задачи? - person Malachiasz; 20.02.2014

слишком поздно ответить, но может быть правильным ответом. Я создал родительский класс, и фрагмент диалога расширяется от него.

 public class BaseDialogFragment extends DialogFragment {

@Override
public void show(FragmentManager manager, String tag) {
    try {
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag).addToBackStack(null);
        ft.commitAllowingStateLoss();
    } catch (IllegalStateException e) {
        Log.d("ABSDIALOGFRAG", "Exception", e);
    }
}

boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;

@Override
public void onResume() {
    onResumeFragments();
    super.onResume();
}

public void onResumeFragments(){
    mIsStateAlreadySaved = false;
    if(mPendingShowDialog){
        mPendingShowDialog = false;
        showSnoozeDialog();
    }
}

@Override
public void onPause() {
    super.onPause();
    mIsStateAlreadySaved = true;
}

private void showSnoozeDialog() {
    if(mIsStateAlreadySaved){
        mPendingShowDialog = true;
    }else{
        FragmentManager fm = getFragmentManager();
        BaseDialogFragment snoozeDialog = new BaseDialogFragment();
        snoozeDialog.show(fm, "BaseDialogFragment");
    }
}

}

person mostafa hashim    schedule 19.11.2017
comment
Хороший ответ, продолжай. - person Subin Babu; 05.04.2018

onPostResume() используйте метод возобновления публикации для выполнения своей работы. Я думаю, что вы вызываете метод show dialog в onRestart или onResume, поэтому избегайте его и используйте onPostResume() для отображения ваш диалог.

person Vikas Kumbhar    schedule 25.06.2015

Вы можете проверить, является ли текущая активность активной(), и только в этом случае запустить фрагментную транзакцию DialogFragment. У меня была аналогичная проблема, и эта проверка решила мой случай.

person box    schedule 01.02.2016

Оно работает:

CheckinSuccessDialog dialog = new CheckinSuccessDialog();
//dialog.show(getSupportFragmentManager(), null);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(dialog, null);
ft.commitAllowingStateLoss();

Но все равно плохо, т.к. вылезла ошибка "Активность уничтожена"

 ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();

Итак, мое решение - добавить проверку if (!isFinishing()&&!isDestroyed())

CheckinSuccessDialog fragment = CheckinSuccessDialog.newInstance();

  if (fragment instanceof DialogFragment) {
                DialogFragment dialog = (DialogFragment) fragment;
                if (!dialog.isAdded()) {
                    fragmentTransaction.add(dialog, 
                          CheckinSuccessDialog.class.getName());
                    if (!isFinishing()&&!isDestroyed()) {
                        fragmentTransaction.commitAllowingStateLoss();
                    }
                }

при увольнении:

  FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            Fragment fragment = getSupportFragmentManager().findFragmentByTag(CheckinSuccessDialog.class.getName());
            if (fragment != null && fragment instanceof DialogFragment) {
                DialogFragment dialog = (DialogFragment) fragment;
                dialog.dismiss();
                if (!isFinishing()&&!isDestroyed()) {
                    fragmentTransaction.commitAllowingStateLoss();
                }
            }
person Serg Burlaka    schedule 13.05.2017

В Activity перед отображением диалога вы можете сделать что-то вроде этого

getSupportFragmentManager().executePendingTransactions();

Это сработало для меня.

person Rino    schedule 09.11.2016