Search code examples
javaandroidrunnableandroid-dialogfragment

Multiple DialogFragments with different functionalities


So i'm developing Android app where user is often asked what he wants to do on some actions (Button click etc.). For that i was using AlertDialog and wrote text on it and added Buttons i needed. It was working super until i realized, that on device rotation, an opened AlertDialog would disappear. I found on the web that the proper way to handle rotation is to use Fragment, so i choose to make class extending DialogFragment:

public class MyDialogFragment extends DialogFragment {

public interface YesNoListener {
    void onYes();
    void onNo();
    void onNeu();
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    String[] data = getArguments().getStringArray("data"); //vzame vrednosti, ki smo jih nastavili preden se pokliče .show();
    if(data != null) {
        switch (data.length) {
            case 3:
                return new AlertDialog.Builder(getActivity())
                        .setTitle(data[0])
                        .setMessage(data[1])
                        .setNeutralButton(data[2], new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onNeu();
                            }
                        })
                        .create();
            case 4:
                return new AlertDialog.Builder(getActivity())
                        .setTitle(data[0])
                        .setMessage(data[1])
                        .setPositiveButton(data[2], new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onYes();
                            }
                        })
                        .setNegativeButton(data[3], new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onNo();
                            }
                        })
                        .create();
            case 5:
                return new AlertDialog.Builder(getActivity())
                        .setTitle(data[0])
                        .setMessage(data[1])
                        .setPositiveButton(data[2], new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onYes();
                            }
                        })
                        .setNegativeButton(data[3], new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onNo();
                            }
                        })
                        .setNeutralButton(data[4], new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ((YesNoListener) getActivity()).onNeu();
                            }
                        })
                        .create();
            default:
                return null;
        }
    }
    else
        return null;
}
}

I used interface too so i could implement Button.onClick() behaviour in the class where i would use MyDialogFragment. With getArguments() i passed all texts that would be used in Dialog.

The problem is that i can only use this class for one Dialog, since i have to Override interface functions, but i have multiple Dialogs with different behaviour.

I wanted to solve this issue with three public Objects Runnable, where i would just initialize Runnable where i need to change the behaviour of the Button.onClick()

...
Runnable runnablePositive, runnableNegative, runnableNeutral;
...

@Override
public void onYes(){
    threadPositive.start();
}

@Override
public void onNo(){
    threadNegative.start();
}

@Override
public void onNeu(){
    threadNeutral.start();
}

static MyDialogFragment newInstance(String[] arg) {
    MyDialogFragment f = new MyDialogFragment();

    Bundle args = new Bundle();
    args.putStringArray("data", arg);
    f.setArguments(args);

    return f;
}

...and on usage:

threadPositive = new Thread()
{
    public void run()
    {
         //do A
    }
};
threadNegative = new Thread()
{
    public void run()
    {
         //do B
    }
};
threadNeutral = new Thread()
{
    public void run()
    {
         //do C
    }
};
newInstance(new String[]{title, besedilo, nevtralno}).show(getFragmentManager(), "tag");

It is working good untill i open Dialog and rotate (this is the main problem, other things somehow work) the device (reason why i use DialogFragment in the first place). All the variables are "deleted" on the rotation and i already passed all variables i needed for further work, but there comes new issue, which i have no idea how to solve: i can't pass Objects on rotation, whether i try with onRetainCustomNonConfigurationInstance() or onSaveInstanceState() all in vain...

So i have no idea how to solve this, i had gone through hundreds of question regarding similar issue, but had no luck... And i would be grateful for any helpful advice or answer regarding this problem (even if it is a different way to solve the problem).

Thanks in advance!


Solution

  • If you have multiple dialogs with different behavior, then you should simply create more instances of your dialog and assign them different tags. Instead of doing just

    newDialogFragment(someArgs).show(getFragmentManager(), "tag")
    

    you can do

    newDialogFragment(someArgs).show(getFragmentManager(), "dialogWithArgs")
    newDialogFragment(someOtherArgs).show(getFragmentManager(), "dialogWithOtherArgs")
    

    and so on. Your interface should be changed to

    public interface YesNoListener {
        void onYes(String tag);
        void onNo(String tag);
        void onNeu(String tag);
    }
    

    When you call its methods from the dialog, pass the fragment tag so you know which dialog called the method. That way you can handle any number of dialogs easily.

    As to saving the objects, those that don't change, go into the arguments, those that do, should be made Parcelable and saved to Bundle, if you can't, then you can create a separate fragment and call setRetainInstance(true) on it, then store the objects in it.