Search code examples
androidandroid-fragmentsandroid-listfragment

Fragment throw IllegalStateException after device orientation change


I have a listfragment in an activity, a dialogfragment will open on pressing on a row for the further options, now I rotate the device and choose a option from dialogfragment, its throws an IllegalStateException .... Fragment is not attached.

            choiceDialog
            .setOnClickListDialogClickListener(new StandardListDialogFragment.OnClickListener<String>() {
                @Override
                public void onClick(DialogInterface dialog, int which,
                        String value) {
                    Intent intent = new Intent(this.getActivity(),
                  DutyEditor.class);        
                 startActivityForResult(intent, 0);
                    dialog.dismiss();
                }
            });

Solution

  • This happens because the Fragment is destroyed and re-created with a FragmentManager whenever orientation changes.

    You should stick to these rules when working with Fragments

    • Avoid setters when using Fragments.
    • Never hold a field reference to a Fragment in an Activity.
    • You can hold a field reference to an Activity on a Fragment after onAttach() and before onDetach(), but I find it better to call getActivity() and check for null every time I need it for short operations.

    The best option is to call startActivityForResult() in the DialogFragment itself.

    But whenever you really need to deliver the DialogFragment click events to the Activity, use an Interface. For example.

    public final class SomeDialogFragment extends DialogFragment {
    
        /**
         * Callbacks of {@link SomeDialogFragment}
         */
        public interface SomeDialogFragmentCallbacks {
            /**
             * Called when user pressed some button
             */
            void onSomeButtonClick();
        }
    
        @Override
        public void onAttach(final Activity activity) {
            super.onAttach(activity);
            // Make sure the Activity can receive callbacks
            if (!(activity instanceof SomeDialogFragmentCallbacks)) {
                throw new RuntimeException("Should be attached only to SomeDialogFragmentCallbacks");
            }
        }
    
    
        // now whenever a button is clicked
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            final SomeDialogFragmentCallbacks callbacks = (SomeDialogFragmentCallbacks) getActivity();
            if (callbacks != null) {
                callbacks.onSomeButtonClick();
            }
        }
    }
    

    And all Activities that use this DialogFragment should implelent the callbacks method.

    public final class SomeActivity extends Activity implements SomeDialogFragmentCallbacks {
    
        @Override
        public void onSomeButtonClick() {
            // Handle some DialogFragment button click here
        }
    
    }