Android Dialog reopen after rotate device

2019-05-18 12:06发布

问题:

I'm writing a very simple application to open my custom share dialog. XML layout contains only 1 button:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white"
    android:gravity="center_horizontal">

    <Button android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:layout_margin="20dip"
        android:text="Click here to open Share Dialog"
        android:onClick="onBtnShareClick"/>

</LinearLayout>

And on Activity, I create a custom sharing Dialog

public class CustomDialog extends Activity {

    private static final int SHOW_DIALOG_SHARE = 1;
    private ArrayAdapter<ShareItem> mShareAdapter;

    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        setContentView(R.layout.custom_dialog);

        final ShareItem[] items = {
            //new Item("Menu item", R.drawable.icon_assistance),
            new ShareItem("Banbe", R.drawable.ic_banbe),
            new ShareItem("Facebook", R.drawable.ic_facebook),
            new ShareItem("Twitter", R.drawable.ic_twitter),
            new ShareItem("Gmail", R.drawable.ic_gmail),
            new ShareItem("Other sharing options...", 0)
        };

        mShareAdapter = new ArrayAdapter<ShareItem>(
        this,
        android.R.layout.select_dialog_item,
        android.R.id.text1,
        items){
            public View getView(int position, View convertView, ViewGroup parent) {
                //User super class to create the View
                View v = super.getView(position, convertView, parent);
                TextView tv = (TextView)v.findViewById(android.R.id.text1);

                //Put the image on the TextView
                tv.setCompoundDrawablesWithIntrinsicBounds(items[position].icon, 0, 0, 0);

                //Add margin between image and text (support various screen densities)
                int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
                tv.setCompoundDrawablePadding(dp5);

                return v;
            }
        };
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
            case SHOW_DIALOG_SHARE:
            return new AlertDialog.Builder(this)
            .setIcon(R.drawable.icon)
            .setTitle(R.string.app_name)
            .setAdapter(mShareAdapter, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int item) {
                    Toast.makeText(CustomDialog.this, "Click on item " + item, Toast.LENGTH_SHORT).show();
                }
            })
            .show();
        }
        return null;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // TODO Auto-generated method stub
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onRestoreInstanceState(savedInstanceState);
    }

    public void onBtnShareClick(View v) {
        showDialog(SHOW_DIALOG_SHARE);
    }

    protected class ShareItem {
        public final String text;
        public final int icon;
        public ShareItem(String text, Integer icon) {
            this.text = text;
            this.icon = icon;
        }
        @Override
        public String toString() {
            return text;
        }
    }

}

When click the button, my Sharing Dialog will be opened. All good.

Now, I rotate the device to portrait mode, click the button to open the Dialog. After that, press back to close Sharing Dialog. Rotate device to landscape mode. Suddenly Sharing Dialog is re-opened although I didn't click on the button.

When I try using the native Sharing Dialog I don't see this bug. Maybe a custom Sharing Dialog is the cause?

Can anyone tell me what's wrong here?

回答1:

Hi You have to add screen orientation support in your application manifest file.

 <activity android:name=".TestApp"
     android:label="@string/app_name"   android:configChanges="orientation">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

And also override the following method ,

  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
  }


回答2:

use create() method instead of show() method

new AlertDialog.Builder(this).create()



回答3:

Try use own class that will be extends from DialogFragment

For example:

    public class QuestionDialogFragment extends DialogFragment
    {
        public final static String BF_TITLE = "QuestionDialogFragment.BF_TITLE";
        public final static String BF_QUESTION = "QuestionDialogFragment.BF_QUESTION";

        private Callback mCallback;

        public static void init(FragmentManager fragmentManager, String title, String question, Callback callback)
        {
            Bundle bundle = new Bundle();
            bundle.putString(BF_TITLE, title);
            bundle.putString(BF_QUESTION, question);

            QuestionDialogFragment dialog = new QuestionDialogFragment();
            dialog.setCallbackListener(callback);
            dialog.setArguments(bundle);
            dialog.show(fragmentManager, null);
        }

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

            setCancelable(false);
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState)
        {
            Bundle bundle = getArguments();

            String title = null;
            String question = null;

            if (bundle != null)
            {
                if (bundle.containsKey(BF_TITLE))
                {
                    title = bundle.getString(BF_TITLE);
                }
                if (bundle.containsKey(BF_QUESTION))
                {
                    question = bundle.getString(BF_QUESTION);
                }
            }

            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
            alertDialogBuilder.setTitle(title);
            alertDialogBuilder.setMessage(question);
            //null should be your on click listener
            alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    mCallback.success();
                    dialog.dismiss();
                }
            });
            alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
            {

                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    mCallback.cancel();
                    dialog.cancel();
                }
            });

            return alertDialogBuilder.create();
        }

        public void setCallbackListener(Callback callback)
        {
            this.mCallback = callback;
        }

        public static interface Callback
        {
            void success();
            void cancel();
        }
}

And use it anywhere in your code:

            QuestionDialogFragment.init(
                getFragmentManager(),
                "Some title",
                "Some question?",
                new QuestionDialogFragment.Callback()
                {
                    @Override
                    public void success()
                    {
                        // @TODO if user choice YES;
                    }

                    @Override
                    public void cancel()
                    {
                        // @TODO if user choice CANCEL;
                    }
                });

If you want create own view instead standard dialog window just instead:

  Dialog onCreateDialog(Bundle savedInstanceState) 

use

  View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

For example:

need create values/layout/your_fragment_layout.xml

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:id="@+id/kom_purchase_dialog_root_view">

        <TextView
            android:id="@+id/kom_purchase_dialog_message_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="some text"/>

        <LinearLayout
            android:layout_gravity="bottom"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:id="@+id/kom_purchase_dialog_negative_button"
                android:layout_alignParentBottom="true"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="Cancel"/>

            <Button
                android:id="@+id/kom_purchase_dialog_positive_button"
                android:layout_toRightOf="@+id/kom_purchase_dialog_negative_button"
                android:layout_alignParentBottom="true"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="Ok"/>
        </LinearLayout>
    </FrameLayout>

and for this layout change own class as:

public class QuestionDialogFragment2 extends DialogFragment
{

    public final static String BF_TITLE = "QuestionDialogFragment.BF_TITLE";
    public final static String BF_QUESTION = "QuestionDialogFragment.BF_QUESTION";

    private Callback mCallback;

    public static void init(FragmentManager fragmentManager, String title, String question, Callback callback)
    {
        Bundle bundle = new Bundle();
        bundle.putString(BF_TITLE, title);
        bundle.putString(BF_QUESTION, question);

        QuestionDialogFragment2 dialog = new QuestionDialogFragment2();
        dialog.setCallbackListener(callback);
        dialog.setArguments(bundle);
        dialog.show(fragmentManager, null);
    }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        Bundle bundle = getArguments();

        String title = null;
        String question = null;

        if (bundle != null)
        {
            if (bundle.containsKey(BF_TITLE))
            {
                title = bundle.getString(BF_TITLE);
            }
            if (bundle.containsKey(BF_QUESTION))
            {
                question = bundle.getString(BF_QUESTION);
            }
        }
        View view = super.onCreateView(inflater, container, savedInstanceState);
        if (view == null)
        {
            view = inflater.inflate(R.layout.your_fragment_layout, null, false);
            view.setTag(new Holder(view));
        }
        Holder holder = (Holder) view.getTag();
        holder.messageTextView.setText(question);
        holder.positiveButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mCallback.success();
            }
        });
        holder.negativeButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mCallback.cancel();
            }
        });
        return view;
    }

    public void setCallbackListener(Callback callback)
    {
        this.mCallback = callback;
    }

    public static interface Callback
    {
        void success();
        void cancel();
    }

    private final class Holder
    {
        public TextView messageTextView;
        public Button positiveButton;
        public Button negativeButton;

        private Holder(View view)
        {
            messageTextView = (TextView) view.findViewById(R.id.question_dialogfragment_message_textview);
            positiveButton = (Button) view.findViewById(R.id.question_dialogfragment_positive_button);
            negativeButton = (Button) view.findViewById(R.id.question_dialogfragment_negative_button);
        }
    }
}

and the same usage:

            QuestionDialogFragment2.init(
                getFragmentManager(),
                "Some title",
                "Some question?",
                new QuestionDialogFragment2.Callback()
                {
                    @Override
                    public void success()
                    {
                        // @TODO if user choice YES;
                    }

                    @Override
                    public void cancel()
                    {
                        // @TODO if user choice CANCEL;
                    }
                });

For both approaches will work void onSaveInstanceState(Bundle outState) and save state after rotation. I think it's better and universal approach then user the simple dialog.



回答4:

It doesn't matter if Dialog or AlertDialog was used. In order to avoid closing the dialog when you rotate screen, use this code:

dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);