java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState with DialogFragment

匆匆过客 提交于 2019-11-28 07:12:46
Khaled Annajar

Here is the answer in another thread:

Actions in onActivityResult and "Error Can not perform this action after onSaveInstanceState"

also here:

Refreshing my fragment not working like I thought it should

This is an example solving this problem:

DialogFragment loadingDialog = createDialog();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                    transaction.add(loadingDialog, "loading");
                    transaction.commitAllowingStateLoss();  
Tran Khanh Tung

I got the same issue and I changed the code as bellow

newFragment.show(transactionFragment, "dialog");

to:

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

the completed code works well for me as bellow, hope that help

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();

Probably, the handler that is responding to the HandleMessage is associated to a destroyed activity.

i.e.: If you rotate the screen, the old destroyed activity will handle the message, then you will call showDialog, and the exception will be thrown:

You are creating a dialog after the old destroyed activity has called his onSaveInstanceState.

Try replacing the callback, with the new created activity, to make sure that you are creating the dialog always in the alive activity.


If you are not rotating, put a flag on onSaveInstance like "saving", and disabling it on onRestoreInstance. In your handleMessage method, if the flag "saving" is on, don't show the dialog, just turn on another flag indicating that the dialog must be created on onResume. Then on onResume method, check if in middle of that process, you should create the dialog, if yes, show it on onResume method.

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

The goal of post() method in this case is to wait while onResume() of Activity or Fragment will finished. It works if you want to show DialogFragment from Fragment., f.e. when you want to show your dialog after a system dialog dismissed.

I was facing the same issue when post delaying Runnables handler.postDelayed(Runnable runnable, long delayed).

I have solved the problem this way:

  1. In onSaveInstanceState I cancel the delayed tasks
  2. In onRestoreInstanceState I recreate the task if there have been delayed tasks when activity was destroyed

too late answer but may be the correct answer. I made a parent class and and dialog fragment extends from it

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

}

onPostResume() use post resume method to do your work.. I think you are calling show dialog method in onRestart or onResume, so avoid it and use onPostResume() to show your dialog.

You could check if the current activity isActive() and only in that case start the fragment transaction of DialogFragment. I had a similar problem and this check solved my case.

It works:

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

But but still bad, because got error “Activity has been destroyed”

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

So my solution is add check 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();
                    }
                }

on dismiss:

  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();
                }
            }

In the Activity, before showing the dialog you can do something like this

getSupportFragmentManager().executePendingTransactions();

This worked for me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!