简体   繁体   中英

How to access own variable upon initialization within inner class?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM