Question

I have found a lot of similar questions on the stackoverflow but their solutions don't work in my case. They are connected with onSaveInstanceState method and the Support Library especially.

I have Activity which runs on one event this code:

MyDialogFragment.showMyDialog(name, this, this);

name parameter is the String object. Second parameter (this) is the just Activity class object and the third one (also this) is the simple interface. This my Activity implements this interface. showMyDialog() is of course static method. This is it body:

MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
fragment.show(activity.getFragmentManager(), "myDialog");

This is working good at the first try. But at the second I am getting this exception:

E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.myapp, PID: 20759
java.lang.IllegalStateException: Activity has been destroyed
        at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1345)
        at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
        at android.app.BackStackRecord.commit(BackStackRecord.java:575)
        at android.app.DialogFragment.show(DialogFragment.java:230)
        at com.example.myapp.view.dialog.MyDialogFragment.showMyDialog(MyDialogFragment.java:41)
        at com.example.myapp.MyActivity.showMyDialog(MyActivity.java:208)
        at com.example.myapp.MyActivity.onEvent(MyActivity.java:232)
        at com.example.myapp.MyActivity.handleMessage(MyActivity.java:89)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)

In general this is the steps to reproduce my exception:

  1. Enter Activity - event is received so MyDialogFragment is shown.
  2. Dismiss dialog by negative button.
  3. Enter Activity once more time - MyDialogFragment is shown again.
  4. Type some code to the EditText.
  5. At this moment validation take some time. Connecting with server etc. And the negative result is returned. So it is need to show MyDialogFragment once more. But at this moment I am getting exception.

However, when I skip the second point and start to typing wrong code for validation, MyDialogFragment will be shown without any issue. Strange behaviour.

I have tried with non-static method, setRetainInstance(true) and also commitAllowingStateLoss. But there was no difference.

Was it helpful?

Solution

It is a bit odd - or maybe just a bug in this Android functionality. I have added block try catch to catch throwing exception in this way:

MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);
try {
    fragment.show(activity.getFragmentManager(), "myDialog");
} catch (Exception e) {
    e.printStackTrace();
}

And of course exception is still throwing (and catching at this moment) and what is interesting my dialog fragment is recreating in correct way and user can interact with it.

OTHER TIPS

In the method showMyDialog() first try :

MyDialogFragment fragment = activity.findFragmentByTag("myDialog");

if (fragment == null), then initialize :

MyDialogFragment fragment = new MyDialogFragment(listener, "Hello " + name);

else show it :

fragment.show(activity.getFragmentManager(), "myDialog");

UPDATE :

void showMyDialog() {
    MyDialogFragment fragment = activity.getFragmentManager().findFragmentByTag("myDialog");
    if (fragment == null) {
        fragment = new MyDialogFragment(listener, "Hello " + name);
    }
    fragment.show(activity.getFragmentManager(), "myDialog");
}

(For API 17 and up)

In case anyone is still having this problem (or even related with a transaction's commit() method) I just added a check before it:

private showFragment() {
    if (isDestroyed()) {
        return;
    }

    // Else do whatever transaction...
}

Just change the below line

MyDialogFragment.showMyDialog(name, this, this);

to

MyDialogFragment.showMyDialog(name, **"Activity class name.this"**, this);

I had the same error while I was trying to add a SupportMapFragment within a DialogFragment. I could fix this error by using getChildFramentManager() instead of getFragmentManager(), as suggested by the API when using nested fragments:

public class GpsDialogFragment extends DialogFragment {
    private SupportMapFragment mapFragment;
    private static final String MAP_FRAGMENT_TAG = "MAP_FRAGMENT";


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.gps_postition_dialog, container, false);
        // ...

        // dynamically create the map fragment (https://stackoverflow.com/questions/14083950)
        FragmentManager fragmentManager = getChildFragmentManager();
        mapFragment = (SupportMapFragment) fragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG);
        if (mapFragment == null) {
            if (!getActivity().isFinishing()) {
                mapFragment = new SupportMapFragment();
                FragmentTransaction ft = fragmentManager.beginTransaction();
                ft.add(R.id.mapFrame, mapFragment, MAP_FRAGMENT_TAG);
                ft.commit();
                fragmentManager.executePendingTransactions();
            }
        }

        return view;
    }

    // ...

    @Override
    public void onPause() {
        if (mapFragment != null)
            getChildFragmentManager().beginTransaction().remove(mapFragment).commit();
        super.onPause();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top