user703232
user703232

Reputation: 61

reuse DialogFragment anywhere

I am developing an app with a few functionalities and whenever there is some error happens in a functionality, an DialogFragment with two buttons will be shown:

  1. Press Positive button to do something
  2. Press Negative button to dismiss itself.

And if an error happens and we have a ErrorManager class to show the error:

public class ErrorManager {
    public static showError(int errorType, FragmentManager fragmentManager) {
        switch(errorType) {
            case 0:
                 new ErrorDialog().setTitle()
                                 .setMessage()
                                 .setPositveButton(()->{
                                       // dosomething when the positive button is clicked
                                    Toast.makeText(getActivity(),.....);
                                 }.show(fragmentManager)
            ...
            default:
            break;              
    }
}

The ErrorManager can be called not only inside the FragmentActivity but anywhere where the FragmentManager can be passed.

and the ErrorDialog is something like:

private ButtonFunction F;
public ErrorDialog extends DialogFragment {
    public interface ButtonFunction {
        void doSomething();
    }
    public ErrorDialog() {

    }

    public void setTitle(String title) {
        // set the title in the bundle
    }

    public void setPositveButton(Function f) {
       this.f = f
    }

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {
    View view = inflater.inflate(getLayoutId(), container, false);
    Button positiveButton = view.findViewById(R.id.postive);
    positiveButton.setOnClickListener(v->{
                    if (f != null) {
                       f.doSomething()
                    }
                    dismiss();
                });
    }
}

By doing this, we can just show the error dialog from ErrorManager class and provide different implementation when the positive button is clicked. Until we turn on the Don't keep Activities from Develop option where the Activity/Fragment view have been destroyed so the "ButtonFunction" is lost.

I have tried the setretaininstance(true) but it works for the orientation change.

I am not sure if set static ButtonFunction f will work or cause any memory leak if the f implementation contains some ParentActivity reference.

Any suggestions? Thanks!

Upvotes: 2

Views: 1121

Answers (2)

Ankit Tale
Ankit Tale

Reputation: 2004

Here is one way to implement it:

public class AlertDialogFragment extends DialogFragment {
    Context context;
    String title, msg, positiveBtnText, negativeBtnText;
    DialogInterface.OnClickListener positiveClickListner, negativeClickListner, itemClickListner;
    DialogInterface.OnKeyListener keyListener;
    String[] items;
    public static boolean mIsDisplayed = false;
    AlertDialog alertDialog;
    private TextView selectedText;
    boolean isPrivacyPopUp = false;
    Date final_firebase_date = null;
    private boolean alertSizeFlag, alertDueDate;
    private int viewAlert;
    private Button postiveButton, negativeButton;

    public AlertDialogFragment() {
    }


    public static AlertDialogFragment getInstance(Context context, String title, String msg, String positiveBtnText, DialogInterface.OnClickListener positiveClickListner, String negativeBtnText, DialogInterface.OnClickListener negativeClickListner, DialogInterface.OnKeyListener keyListener, Date final_firebase_date, boolean isPrivacyPopUP) {
        AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
        alertDialogFragment.context = context;
        alertDialogFragment.title = title;
        alertDialogFragment.msg = msg;
        alertDialogFragment.positiveBtnText = positiveBtnText;
        alertDialogFragment.negativeBtnText = negativeBtnText;
        alertDialogFragment.positiveClickListner = positiveClickListner;
        alertDialogFragment.negativeClickListner = negativeClickListner;
        alertDialogFragment.keyListener = keyListener;
        alertDialogFragment.isPrivacyPopUp = isPrivacyPopUP;
        alertDialogFragment.final_firebase_date = final_firebase_date;
        return alertDialogFragment;
    }

    public static AlertDialogFragment getInstance(Context context, String title, String msg, String positiveBtnText, DialogInterface.OnClickListener positiveClickListner, String negativeBtnText, DialogInterface.OnClickListener negativeClickListner, DialogInterface.OnKeyListener keyListener) {
        AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
        alertDialogFragment.context = context;
        alertDialogFragment.title = title;
        alertDialogFragment.msg = msg;
        alertDialogFragment.positiveBtnText = positiveBtnText;
        alertDialogFragment.negativeBtnText = negativeBtnText;
        alertDialogFragment.positiveClickListner = positiveClickListner;
        alertDialogFragment.negativeClickListner = negativeClickListner;
        alertDialogFragment.keyListener = keyListener;
        alertDialogFragment.isPrivacyPopUp = false;
        return alertDialogFragment;
    }

    //Create custom Constructor with parameter

    @Override
    public void onStart() {
        super.onStart();
        if (isPrivacyPopUp) {
            TextView textPrivacyMsg = ((TextView) alertDialog.findViewById(android.R.id.message));
            if (textPrivacyMsg != null) {
                textPrivacyMsg.setMovementMethod(LinkMovementMethod.getInstance());
                textPrivacyMsg.setText(xxxxxxxx.addClickablePartForPrivacy1(context,
                        getResources().getString(R.string.privacy_popup_note),
                        R.string.privacy,
                        R.string.privacy_link, R.color.blue, final_firebase_date, alertDialog), TextView.BufferType.SPANNABLE);

            }
        }

        if (alertSizeFlag == true) {
            if (getDialog().getWindow() != null) {
                if(LandingScreenPhoneActivity.isTablet(getActivity())){
                    getDialog().getWindow().setLayout(CommonBindingUtils.getRelativeWidthInPX(150), WindowManager.LayoutParams.WRAP_CONTENT);
                    PreferencesManager.getInstance().putBoolean(ALERT_FLAG, false);
                }
                else{
                    getDialog().getWindow().setLayout(CommonBindingUtils.getRelativeWidthInPX(280),WindowManager.LayoutParams.WRAP_CONTENT);
                    PreferencesManager.getInstance().putBoolean(ALERT_FLAG, false);
                }

            }
        }

        if (alertDueDate == true) {
            if (getDialog().getWindow() != null ) {
                if(LandingScreenPhoneActivity.isTablet(getActivity())){
                    getDialog().getWindow().setLayout(CommonBindingUtils.getRelativeWidthInPX(150), WindowManager.LayoutParams.WRAP_CONTENT);
                   // getDialog().getWindow().setLayout(CommonBindingUtils.getRelativeWidthInPX(150), CommonBindingUtils.getRelativeHeightInPX(150));

                }
                else{
                    getDialog().getWindow().setLayout(CommonBindingUtils.getRelativeWidthInPX(280),WindowManager.LayoutParams.WRAP_CONTENT);

                }

            }
        }

        //Crash fix #178
        if (alertDialog!=null){
            negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
            postiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
        }


        if (postiveButton != null) {
            postiveButton.setTextColor(getResources().getColor(R.color.new_colorPrimary));
        }
        if (negativeButton != null) {
            negativeButton.setTextColor(getResources().getColor(R.color.new_colorPrimary));
        }

        // getDialog().getWindow().setLayout(200,200);

    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        int checkedItem = -1;


        alertSizeFlag = PreferencesManager.getInstance().getBoolean(ALERT_FLAG);

        alertDueDate = PreferencesManager.getInstance().getBoolean(DUE_DATE_ALERT);

        if (items != null && selectedText != null) {
            checkedItem = Arrays.asList(items).indexOf(selectedText.getText().toString());
        }


        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.customalertstyle)
                // set dialog icon
                // set Dialog Title
                .setTitle(title)
                // Set Dialog Message
                .setItems(items, itemClickListner)
                .setMessage(msg)
                // positive button
                .setCancelable(false)
                .setPositiveButton(positiveBtnText, positiveClickListner)
                .setOnKeyListener(keyListener)
                .setNegativeButton(negativeBtnText, negativeClickListner);

        if (viewAlert != 0 && alertDueDate == true) {
            builder.setView(viewAlert);
        }

        if (selectedText != null) {
            builder.setSingleChoiceItems(items, checkedItem, itemClickListner);
        }
        alertDialog = builder.create();
        alertDialog.setCanceledOnTouchOutside(false);

        if (isPrivacyPopUp) {
            Window window = alertDialog.getWindow();
            window.setGravity(Gravity.BOTTOM);
            window.setLayout(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT);
        }

        return alertDialog;
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        //to catch the exception while app is in background and dialog
        try {
            super.show(manager, tag);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void dismiss() {
        super.dismiss();
        xxxxxxxx.resetBellyCount();
        mIsDisplayed = false;
        clearReferences();
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);

        xxxxxxxx.resetBellyCount();
        mIsDisplayed = false;
        xxxxxxxx.resetBellyCount();
        mIsDisplayed = false;
        clearReferences();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        clearReferences();
    }

    private void clearReferences() {
        context = null;
        title = null;
        msg = null;
        positiveBtnText = null;
        negativeBtnText = null;
        positiveClickListner = negativeClickListner = itemClickListner = null;
        keyListener = null;
        items = null;
        alertDialog = null;
        selectedText = null;
        final_firebase_date = null;
    }
}

Upvotes: 0

Tushar Pandey
Tushar Pandey

Reputation: 550

Xml for custom dialog

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/genericDialog"
    android:layout_width="280dp"
    android:layout_height="180dp"
    android:layout_gravity="center"
    android:layout_margin="8dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <TextView
        android:id="@+id/dialogMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:gravity="center"
        android:padding="10dp"
        android:text="Your Custom Message"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp"
        app:layout_constraintBottom_toTopOf="@+id/negativeCLick"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.502"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/positiveClick"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginBottom="16dp"
        android:gravity="center"
        android:padding="10dp"
        android:text="Yes"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/negativeCLick"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="24dp"
        android:layout_marginBottom="16dp"
        android:gravity="center"
        android:padding="10dp"
        android:text="No"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


Java code custom Dialog

    // 3 Params: 1st- Activity, 2nd- Dialog Message, 3-New Activity of action you want to do.
    public static void showDialogWithYesNo(Activity activity, String msg, Class gotoActivity) {
        final Dialog dialog = new Dialog(activity, android.R.style.Theme_Dialog);
        int layout_parms;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layout_parms = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            layout_parms = WindowManager.LayoutParams.TYPE_PHONE;
        }

        new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                layout_parms,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSPARENT);

        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setCancelable(false);
        dialog.setContentView(R.layout.generic_dialog);
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(activity.getResources().getColor(R.color.colorPrimary)));
        dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

        TextView text = (TextView) dialog.findViewById(R.id.dialogMessage);
        text.setText(msg);

        TextView dialogBtn_cancel = (TextView) dialog.findViewById(R.id.negativeCLick);
        dialogBtn_cancel.setText("No");
        dialogBtn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.cancel();
            }
        });

        TextView dialogBtn_okay = (TextView) dialog.findViewById(R.id.positiveClick);
        dialogBtn_okay.setText("Yes");
        dialogBtn_okay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

// Add actions as per your need here for positive response
                Intent intent = new Intent(activity, gotoActivity);
                activity.startActivity(intent);
                dialog.cancel();
            }
        });

        dialog.show();
    }

How to use the above dialog

    //1: Activity.this will your Activity Name.this 
    //2: Your Message you want to display in your dialog
    //3: The Activity you want to open when a user press yes. eg: NewAcitivity.class

    showDialogWithYesNo(Activity.this, "Do you want to exit ?", Activity.class);

Upvotes: 1

Related Questions