iseeall
iseeall

Reputation: 3431

Properly closing custom dialog

I'd like to easily display custom-style popups across the whole application. For that in my Utils class I created this static method:

public static Dialog showStyledPopup(Context context, String sHeader, String sMessage, 
            String sBtn0Text, View.OnClickListener onClick0,
            String sBtn1Text, View.OnClickListener onClick1,
            String sBtn2Text, View.OnClickListener onClick2)
    {
        Dialog dialog = new Dialog(context, R.style.dialog_style_no_bg);
        dialog.setContentView(R.layout.popup);
        dialog.setCancelable(false);
        TextView txtHeader = (TextView)dialog.findViewById(R.id.txt_popup_header);
        if (null == sHeader)
        {
            txtHeader.setVisibility(View.GONE);
        }
        else
        {
            txtHeader.setText(sHeader);
            txtHeader.setTypeface(App.fontHeader);
        }
        TextView txtMessage = (TextView)dialog.findViewById(R.id.txt_popup_message);
        txtMessage.setText(sMessage);
        txtMessage.setTypeface(App.fontCommon);
        Button btn0 = (Button)dialog.findViewById(R.id.btn_popup_0);
        btn0.setVisibility(View.VISIBLE);
        btn0.setText(sBtn0Text);
        btn0.setTypeface(App.fontCommon);
        btn0.setOnClickListener(onClick0);
        if (null != onClick1)
        {
            Button btn1 = (Button)dialog.findViewById(R.id.btn_popup_1);
            btn1.setVisibility(View.VISIBLE);
            btn1.setText(sBtn1Text);
            btn1.setTypeface(App.fontCommon);
            btn1.setOnClickListener(onClick1);
        }
        if (null != onClick2)
        {
            Button btn2 = (Button)dialog.findViewById(R.id.btn_popup_2);
            btn2.setVisibility(View.VISIBLE);
            btn2.setText(sBtn2Text);
            btn2.setTypeface(App.fontCommon);
            btn2.setOnClickListener(onClick2);
        }
        dialog.show();
        return dialog;
    }

popup.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="250dp"
    android:layout_height="170dp"
    android:background="@drawable/dialog_250_170"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/txt_popup_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
        android:textColor="@android:color/black"
        android:textSize="20dp" />

    <LinearLayout
        android:id="@+id/group_popup_btns"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal"
        android:baselineAligned="false" >

        <Button
            android:id="@+id/btn_popup_0"
            android:layout_width="60dp"
            android:layout_height="40dp"
            android:background="@drawable/btn_60_40"
            android:textColor="@android:color/black"
            android:textSize="20dp" />

        <Button
            android:id="@+id/btn_popup_1"
            android:layout_width="60dp"
            android:layout_height="40dp"
            android:layout_marginLeft="5dp"
            android:background="@drawable/btn_60_40"
            android:textColor="@android:color/black"
            android:textSize="20dp"
            android:visibility="gone" />

        <Button
            android:id="@+id/btn_popup_2"
            android:layout_width="60dp"
            android:layout_height="40dp"
            android:layout_marginLeft="5dp"
            android:background="@drawable/btn_60_40"
            android:textColor="@android:color/black"
            android:textSize="20dp"
            android:visibility="gone" />
    </LinearLayout>
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@id/group_popup_btns"
        android:layout_below="@id/txt_popup_header"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp" >
        <ScrollView
            android:id="@+id/scroll_popup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
             >
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/txt_popup_message"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:textColor="@android:color/black"
                    android:textSize="18dp" />
            </LinearLayout>
        </ScrollView>
    </RelativeLayout>
</RelativeLayout>

in styles.xml:

<style name="dialog_style_no_bg"  parent="@android:style/Theme.Dialog">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

The caller is supposed to pass the View.OnClickListeners. To be able to close the dialog, the caller must have Dialog dialog field which is then used in the OnClickListener to dismiss the dialog, e.g.:

this.dialog = Utils.showStyledPopup(this, null, getString(R.string.STR_ENABLE_SOUND_AND_MUSIC_Q), 
                    getString(R.string.STR_YES), new View.OnClickListener()
                    {
                        @Override
                        public void onClick(View v)
                        {
                            doToggleSound();
                            doToggleMusic();
                            dialog.dismiss();
                            dialog = null;
                        }
                    }, getString(R.string.STR_NO), new View.OnClickListener()
                    {
                        @Override
                        public void onClick(View v)
                        {
                            dialog.dismiss();
                            dialog = null;
                        }
                    });

The problem is that for some reason in rare cases the dialog field gets reset while the popup is still shown. I can't reproduce this, but got a few crash reports because of this in the field.

Has someone tried to do the same?

The activity has it's orientation fixes to landscape, so onCreate should never get called in-between to reset dialog variable.

I don't like the idea of storing the reference to the dialog, but there is just no way to use a final variable in this case, because it gets a value after it should be passed to the OnClickListener.

My question is similar to Android close custom dialog but the problem there is also not solved, at least as I want it (as 1 method in Utils).

I've seen onCreate() being called on DellStreak device at weird times, so this might be just some device-specific issue (PMP5080BRU)

Upvotes: 0

Views: 578

Answers (1)

0xC0DED00D
0xC0DED00D

Reputation: 20348

The solution would be to declare Dialog dialog as class field, declare it at class level.

EDIT
Try this solution too. Have the dialog as class field in the Utils class. Do not return the dialog object from the method, instead use it to initialize the dialog variable. The use a getter method (or try accessing directly though not recommended) of dialog variable. This is kinda dirty solution, but it might work for you too.

Upvotes: 1

Related Questions