12

I'm developing a launcher application that shows a dialogfragment when the user authenticates itself. Most of the times this is working well, but sometimes I'm having this error log:

02-07 18:55:56.619: E/AndroidRuntime(1300): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1280)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1291)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.BackStackRecord.commit(BackStackRecord.java:532)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.DialogFragment.dismissInternal(DialogFragment.java:292)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.DialogFragment.dismiss(DialogFragment.java:258)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.blablabla.android.app.fragments.login.LoginResultFragment$CloseDialogRunnable.run(LoginResultFragment.java:59)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Handler.handleCallback(Handler.java:615)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Handler.dispatchMessage(Handler.java:92)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Looper.loop(Looper.java:137)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.ActivityThread.main(ActivityThread.java:4745)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at java.lang.reflect.Method.invokeNative(Native Method)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at java.lang.reflect.Method.invoke(Method.java:511)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at dalvik.system.NativeStart.main(Native Method)

I've searched in other threads, for example and followed their suggestions, but it's still not working for me

My dialogfragment looks like:

public class LoginResultFragment extends DialogFragment implements
        OnClickListener {

    private CloseDialogRunnable runnable = null;

    public class CloseDialogRunnable implements Runnable {
        /**
         * https://stackoverflow.com/questions/5844308/removecallbacks-not-
         * stopping-runnable
         */
        private boolean killCloseActivityRunnable = false;

        public void killRunnable() {
            killCloseActivityRunnable = true;
        }

        @Override
        public void run() {
            if (killCloseActivityRunnable) {
                return;
            }
            if (getDialog()!=null && getDialog().isShowing()) {             
                    dismiss();              
            }
        }
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        if (runnable != null){      
            runnable.killRunnable();
            handler.removeCallbacks(runnable);
        }
        super.onDismiss(dialog);
    }

    /** Milliseconds until we dismiss the timeout */
    private static final long DISMISSING_TIMEOUT = 2000;

    /** Dismissing window handler */
    private final Handler handler = new Handler();

    private LoginResultFragment() {
    }

    public static LoginResultFragment getInstance(
            Map<String, Object> currentValues) {
        LoginResultFragment result = new LoginResultFragment();

        set extra fields...

        return result;
    }


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

        setStyle(DialogFragment.STYLE_NO_FRAME,
                android.R.style.Theme_Holo_Dialog);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        setRetainInstance(true);
        rootView = inflater.inflate(R.layout.fragment_login_result, container);

        getDialog().getWindow().setBackgroundDrawable(
                new ColorDrawable(android.graphics.Color.TRANSPARENT));

        do UI stuff...

        dismissAfterTimeout();
        return rootView;
    }

    private void dismissAfterTimeout() {
        runnable = new CloseDialogRunnable();
        handler.postDelayed(runnable, DISMISSING_TIMEOUT);

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
    }

}

And I call it with:

final android.app.FragmentTransaction trans = activity
                .getFragmentManager().beginTransaction();
        trans.add(fragment, fragment.getClass().getCanonicalName());
        trans.commitAllowingStateLoss();
Community
  • 1
  • 1
Guillermo Merino
  • 3,197
  • 2
  • 17
  • 34
  • Can you add more detail around where you do the FragmentTransaction? I see you are adding the fragment to the transaction manager, but are you adding it to the layout? What happens next that might case the onSaveInstanceState() to be called on the Fragment (pause, finish activity, etc.)? – jacobhyphenated Feb 07 '14 at 19:11
  • Hi jacobhyphenated, thanks for your comment. I'm not adding the fragment to the layout because i'm showing it like a dialog (it's a DialogFragment). I show it when I receive some login information from other process. – Guillermo Merino Feb 10 '14 at 08:39
  • possible duplicate of [Show DialogFragment from onActivityResult](http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult) – rds Aug 18 '15 at 10:53
  • I've made an alternative solution to DialogFragment, that can avoid this exception : https://github.com/AndroidDeveloperLB/DialogShard – android developer Oct 25 '16 at 08:11

2 Answers2

12

You can use the following:

if (!StartActivity.this.isFinishing())
{
    //showdialog fragment
}

to check if the activity is not finishing just before you show the dialog.

Arno van Lieshout
  • 1,570
  • 1
  • 13
  • 19
1

Finally, the solution for the problem was to modify the CloseDialogRunnable, here is the working code:

public class CloseDialogRunnable implements Runnable {
    /**
     * http://stackoverflow.com/questions/5844308/removecallbacks-not-
     * stopping-runnable
     */
    private boolean killCloseActivityRunnable = false;

    public void killRunnable() {
        killCloseActivityRunnable = true;
    }

    @Override
    public void run() {
        if (killCloseActivityRunnable) {
            return;
        }
        if (getDialog() != null && getDialog().isShowing() && isResumed()) {
            try {
                dismiss();
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Error dismissing");
            }
        }
    }
}
Guillermo Merino
  • 3,197
  • 2
  • 17
  • 34
  • 3
    IllegalArgumentException or IllegalStateException? All you are doing is to swallow the exception. I don't think this is really a solution. Solution would prevent the exception. – rpattabi Jul 03 '16 at 02:29