0

I have a "DialogHelper" class wherein a bunch of static methods are used in various contexts to make using Dialogs easier. One such method is a "three choice dialog" where the user has three buttons to choose from to go forward:

    public static AlertDialog createThreeChoiceDialog(final MyActivity activity, String title, String firstChoiceText,
            String secondChoiceText, String thirdChoiceText, View.OnClickListener firstChoiceListener, View.OnClickListener secondChoiceListener,
            View.OnClickListener thirdChoiceListener) {
        final View dView = activity.getLayoutInflater().inflate(R.layout.three_choice_dialog, null);
        final TextView explanatoryTV = (TextView) dView.findViewById(R.id.explanatoryTV);
        final TextView firstChoiceTV = (TextView) dView.findViewById(R.id.firstChoiceTV);
        final TextView secondChoiceTV = (TextView) dView.findViewById(R.id.secondChoiceTV);
        final TextView thirdChoiceTV = (TextView) dView.findViewById(R.id.thirdChoiceTV);

        explanatoryTV.setText(title);
        firstChoiceTV.setText(firstChoiceText);
        secondChoiceTV.setText(secondChoiceText);
        thirdChoiceTV.setText(thirdChoiceText);

        firstChoiceTV.setOnClickListener(firstChoiceListener);
        secondChoiceTV.setOnClickListener(secondChoiceListener);
        thirdChoiceTV.setOnClickListener(thirdChoiceListener);

        AlertDialog = etc...
        return alertDialog;
    }

And I call it like this:

    private void doSomething() {
        final AlertDialog alert = DialogHelper.createThreeChoiceDialog(activity, "title", "choice1", "choice2", "choice3",
                new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 1

                alert.dismiss();
            }
        }, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 2

                alert.dismiss();
            }
        }, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 3

                alert.dismiss();
            }
        });

        alert.show();
    }

However, the "alert.show()" method rings up the error:

variable 'alert' might not have been initialized yet

My question is, what is the best way to handle this situation? I want to dismiss the dialog when the user selects a choice.

This is my current workaround:

    private void doSomething() {
        final ArrayList<AlertDialog> alerts = new ArrayList<>(); //<-- added ArrayList of AlertDialogs

        final AlertDialog alert = DialogHelper.createThreeChoiceDialog(activity, "title", "choice1", "choice2", "choice3",
                new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 1

                alerts.get(0).dismiss(); //<-- accessed via ArrayList
            }
        }, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 2

                alerts.get(0).dismiss(); //<-- accessed via ArrayList
            }
        }, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do something 3

                alerts.get(0).dismiss(); //<-- accessed via ArrayList
            }
        });

        alerts.add(alert); //<-- add alert to ArrayList
        alert.show();
    }

It works, but there's no way that this can be a best practice. I've run into this problem a few times, so I finally decided to ask what the best way to handle it is.

5
  • These are two unrelated things in my opinion. variable 'alert' might not have been initialized yet is just a warning and not an actual error, right? And I think you can use a final variable inside the inner class like alert.dismiss() instead of alerts.get(0).dismiss(). Commented Aug 23, 2016 at 8:14
  • replace alert.dismiss(); with this.dismiss(); Commented Aug 23, 2016 at 8:16
  • Well, the project won't build with 'alert.dismiss()' unless I turn off the check for that error. Commented Aug 23, 2016 at 8:17
  • this.dismiss() won't work because this points to onClickListener and not the alertDialog. Commented Aug 23, 2016 at 8:26
  • @SFitz Does my answer address your question, or is something not covered? Commented Aug 24, 2016 at 8:32

1 Answer 1

1

You are basically trying to reference an instance of a class while declaring and creating that instance - this is not possible.

I see your options as the following:

1. Wrap AlertDialog

This is basically your work-around which uses an ArrayList, but you can create you own class for this purpose also.

2. Make AlertDialog a member

Declare alert be a private member of the class which contains the doSomething method, instead of declaring it in the method itself.

3. Replace your DialogHelper with a Builder

There are several advantages (and 1 disadvantage) to this approach.

The first advantage is that it will solve your problem. The second is because it's good coding practice: in general, having methods with take many parameters is considered dirty. In the case of them being constructor methods, Clean Code conventions recommend replacing them with builders.

The disadvantage of the implementation I am about to suggest is that the Dialog behaviour is that clicking an option will always dismiss the dialog.

public class MyDialogBuilder {

private AlertDialog alert;

public MyDialogBuilder withActivity(Activity activity){
    final View dView = activity.getLayoutInflater().inflate(R.layout.three_choice_dialog, null);
    alert = ...;
    return this;
}

public MyDialogBuilder withFirstChoice(String choiceText, final ChoiceAction action){
    final TextView firstChoiceTV = (TextView) alert.findViewById(R.id.firstChoiceTV);
    firstChoiceTV.setText(choiceText);
    firstChoiceTV.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            action.perform();
            alert.dismiss();
        }
    });
    return this;
}

// Similar implementations for the other methods here...


public AlertDialog create() {
    return alert;
}

interface ChoiceAction {
    void perform();
}
}

Your calling code would be like

MyDialogBuilder builder = new MyDialogBuilder();
    AlertDialog alert = builder.withActivity(activity)
                               .withTitle("Dialog title")
                               .withFirstChoice("choice 1", new MyDialogBuilder.ChoiceAction() {
                                   @Override
                                   public void perform() {
                                       //do something 1
                                   }
                               })
                               .withSecondChoice("choice 2", new MyDialogBuilder.ChoiceAction() {
                                   @Override
                                   public void perform() {
                                       //do something 2
                                   }
                               })
                               .withThirdChoice("choice 3", new MyDialogBuilder.ChoiceAction() {
                                   @Override
                                   public void perform() {
                                       //do something 3
                                   }
                               })
                               .create();

I would recommend the third approach, as I think in most cases you want to close the Dialog when the user selects an option. If you want to show some progress bar in the dialog, you can create additional methods on MyDialogBuilder which would call alert.dismiss() in a callback. Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.