I have a method:
void someMethod(String someString)
final String[] testAgainst = {...};
....
for(int i = 0; i < testAgainst.length; i++) {
if (someString.equals(testAgainst[i])) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Strings are the same! Overwrite?")
.setTitle("Blah Blah Blah")
.setCancelable(false)
.setPositiveButton("Overwrite", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int which) {
someAction()
}
})
.setNegativeButton("Nah", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int which) {
ESCAPE
}
});
AlertDialog dialog = builder.create();
}
}
doSomeOtherStuff();
}
Here's the thing, if my code reaches ESCAPE (that is, the user decides not to overwrite), I want to exit the method completely. I have tried...
changing someMethod() to return a boolean, then returning it from the negative button, but it won't let me because it's within a void internal method.
throwing an exception from ESCAPE to be caught externally, but the compiler won't let me because DialogInterface.OnClickListener doesn't throw.
using a break statement to leave the for loop, but that doesn't work either.
It would also be acceptable to simply leave the for loop. I can account for that. I've tried everything I can find and I'm at my wit's end.
You can throw a RuntimeException or one of its subclasses. The compiler won't complain about it.
You are not in the loop when that method executes. It may have access to the variables declared there (if they are final), but the OnClickListener is executed once they click, completely outside of/removed from that loop.
You could enhance your code with:
// Static class that contains nothing but a trigger to exit the loop
static class Cancel { boolean shouldCancel = false; }
void someMethod(String someString)
final String[] testAgainst = {...};
....
// Initialize it `final`, else it won't be accessible inside
final Cancel trigger = new Cancel();
// Add the check as additional condition for the `for` condition
for(int i = 0; i < testAgainst.length && !trigger.shouldCancel; i++) {
if (someString.equals(testAgainst[i])) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Strings are the same! Overwrite?")
.setTitle("Blah Blah Blah")
.setCancelable(false)
.setPositiveButton("Overwrite", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int which) {
someAction()
}
.setNegativeButton("Nah", new DialongInterface.OnClickListener() {
public void onClick(DialogInterface di, int which) {
// Use the trigger to communicate back that it's time to finish
trigger.shouldCancel = true;
}
AlertDialog dialog = builder.create();
}
}
doSomeOtherStuff();
}
Android has other methods of doing that too, like Handlers etc.
Related
In the code, there is an alert box(for logout functionality).
This alert box is created inside a method (i.e. logout method) and then two onClickListener are anonymously added to it.
How can I call these anonymous listeners from outside?
Code:
AlertDialog.Builder builder
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id) {
//some logic
}
}
What I need is to somehow call this onClick method and pass the instance of same dialog box.
I have read examples of doing this with reflection, but in those examples anonymous class was a subclass i.e. return value of 'new' was catched
You could make the listener into a field variable.
private final DialogInterface.OnClickListener dialogYesListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//some logic
}
};
AlertDialog.Builder builder
builder.setPositiveButton("Yes", dialogYesListener);
You have two options:
1) Refactor your code to have a reference to an instance of an DialogInterfact.OnClickListener like this:
AlertDialog.Builder builder;
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//some logic
}
}
builder.setPositiveButton("Yes", listener);
2) I don't know whether there is such an API, but if yes, you can try to extract listener implementation from a builder. Pseudocode should look like this:
DialogInterface.OnClickListener listener =
builder.getPositiveButton().getListener(); //adjust this to a real API
I'm new to Java/ Android development (I started learning last night) so it is entirely possible I'm doing something horrendously stupid. However, after more than an hour Googling I've come up with nothing. I'm using Eclipse as my editor.
I'm reading the docs here for AlertDialog, which gives an example:
public static class MyAlertDialogFragment extends DialogFragment {
public static MyAlertDialogFragment newInstance(int title) {
MyAlertDialogFragment frag = new MyAlertDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.alert_dialog_icon)
.setTitle(title)
.setPositiveButton(R.string.alert_dialog_ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((FragmentAlertDialog)getActivity()).doPositiveClick();
}
}
)
.setNegativeButton(R.string.alert_dialog_cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((FragmentAlertDialog)getActivity()).doNegativeClick();
}
}
)
.create();
}
}
I originally re-wrote it so I can start committing some of the methods to memory, but got an error "FragmentAlertDialog cannot be resolved to a type". I hit Ctrl+Shift+O to make sure I had the proper imports, but still it didn't go away.
So I copied/ pasted the example code and did the following, in this order:
Hit Ctrl+Shift+O to get the imports right (using android.app.DialogFragment, not android.support.v4.app.DialogFragment)
Declared my package at the top
Replaced R.string.alert_dialog_ok and R.string.alert_dialog_cancel with android.R.string.ok and android.R.string.cancel respectively
Removed setIcon(), as I don't have an icon to put in yet
I'm still getting errors:
FragmentAlertDialog cannot be resolved to a type (x4)
Illegal modifier for the class MyAlertDialogFragment; only public, abstract & final are permitted
Am I doing something wrong, or is there something wrong with the example code?
1.FragmentAlertDialog
Make sure the Activity you want to cast to is named FragmentAlertDialog. Make sure to also save everything - sometimes Eclipse won't make the connection until everything is saved.
2.Illegal modifier for the class MyAlertDialogFragment; only public, abstract & final are permitted
Take out the static modifier:
public class MyAlertDialogFragment extends DialogFragment {
or keep static and move this Fragment so it is enclosed within the Activity you want. This means that MyAlertDialogFragment should be inside your Activity, before that Activity's closing brace.
I'm new to Java/Android development
Don't start off with something so complicated. Learn Java then move to Android.
Hi try these code to implement alert dialog
AlertDialog.Builder alert2 = new AlertDialog.Builder(this);
alert2.setTitle("Your Title");
alert2.setMessage("Your Messages");
final EditText input2 = new EditText(this);
input2.setInputType(InputType.TYPE_CLASS_PHONE);
alert2.setView(input2);
alert2.setPositiveButton(GButton, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do something with value!
try
{
// do your stuff here
}
catch(Exception e)
{
}
}
});
alert2.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert2.show();
I'm currently writing a program that will use the Geocoder to search for possible GeoPoints of a city search. I then take the geopoints and add it to a map as overlays, the user can then click the overlay, and an alert dialog will pop up to ask if he/she is sure that this is the right one.
I couldn't figure out a way to get the alert dialog to work like swing where after the user clicks yes or no, I can retrieve the answer. So I extended the AlertDialog.Builder class like so, which also happens to be a Dialog.OnClicklistener
public class MyAlertDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener{
final static int positiveMessage = 1;
final static int negativeMessage = 0;
final static int neutralMessage = -1;
private int myMessage;
public MyAlertDialog(Context activity) {
super(activity);
}
#Override
public void onClick(DialogInterface dialog, int which) {
if(which == dialog.BUTTON_POSITIVE){
myMessage = positiveMessage;
}
else if(which == dialog.BUTTON_NEGATIVE){
myMessage = negativeMessage;
}
else{
myMessage = neutralMessage;
}
}
public int getMessage() {
return myMessage;
}
and I implement it like so
protected boolean onTap(int index) {
OverlayItem item = overlays.get(index);
MyAlertDialog dialog = new MyAlertDialog(ctx);
dialog.setTitle(item.getTitle());
dialog.setMessage("Is this the " + item.getTitle()
+ " you're looking for?");
dialog.setPositiveButton("Yes",null);
dialog.setNegativeButton("Cancel", null);
dialog.show();
if(dialog.getMessage()== MyAlertDialog.positiveMessage){
//do some stuff
But for some reason the dialog wont show until after the method has returned, so it never does the stuff. Anyone have any ideas? Oh and ctx is a reference to my mapActivity
This is because the dialog.show(); method does not wait for the user to interact with the Dialog before returning. It does exactly what the name would suggest, and nothing more; it shows the Dialog, and then returns. So, that means that your myMessage field will always be null and this condition will never be true:
if(dialog.getMessage()== MyAlertDialog.positiveMessage){
What you should do instead is pass in OnClickListener for both your positive and negative button, and do whatever you need to in the respective OnClickListener. You won't even need to make a subclass of AlertDialog.Builder, because there won't be any benefit to doing that. Here's how that looks:
dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which){
// Do some positive stuff here!
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which){
// Do some negative stuff here!
}
});
I know that creating static methods to create AlertDialogs is not a good sign. But, whenever I felt like creating some AlertDialogs, I always have to place them inside an Activity subclass. I've been looking around in SO, trying to find a good way to factor the code, so that I don't have to initialize and create AlertDialogs from an Activity subclass.
Here is an example of my code, designed in such a way that I have to sacrifice performance speed for AlertDialogs, which is very necessary in my project plans.
public void onCreate(Bundle b) {
super.onCreate(b);
accelerometer = new Accelero();
leaderboard = new Score(this);
renderView = new RenderView(this);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(renderView);
// TODO: Refactor this, to speed things up.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
input = new EditText(this);
builder.setView(input);
builder.setTitle("Enter Name for High Score!");
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO: Polish the dialog.
// TODO: Add a method of obtaining the score from RenderView.
renderView.getStage().reset();
renderView.setDialogFlag(false);
}
});
builder.setNegativeButton("Back", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
PlayActivity.this.onBackPressed();
}
});
renderView.setLosingDialog(builder.create());
builder = new AlertDialog.Builder(this);
builder.setTitle("You win!");
builder.setPositiveButton("Next Stage", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
renderView.createStage(getAssets(), stageNumber);
renderView.pauseGame();
}
});
renderView.setWinningDialog(builder.create());
builder = new AlertDialog.Builder(this);
builder.setTitle("Game Paused!");
builder.setPositiveButton("Back to Game", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
renderView.unpauseGame();
}
});
builder.setNeutralButton("Restart", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
renderView.resetGame();
}
});
builder.setNegativeButton("Main Menu", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO: Will probably improve some more on this.
PlayActivity.this.finish();
}
});
renderView.setPausingDialog(builder.create());
}
This isn't what I wanted. I tried placing them in a new thread to run, but it leaks memory, so it didn't work. Also, due to issues (Static AlertDialog methods will leak memory, etc.), I just don't have any other ideas on fixing this.
I don't know what to do next. So, may I ask, who else have a better way of initializing AlertDialogs without sacrificing performance speeds? Thanks in advance.
First thing I would do is to add some performance analysis instrumentation (measurements) to determine where the code is spending its time. Nothing is more painful than spending time trying to optimize something that doesn't need optimization ;-)
From looking at this I can see at least one simple optimization: This code creates 6 instances of 6 different anonymous classes just to handle the onClick() callbacks. IMHO that isn't necessary. You could just use this as the callback interface and make sure that your activity implements DialogInterface.OnClickListener. Then write a single method in your activity that handles all the click events:
public void onClick(DialogInterface dialog, int which) {
if (dialog == renderView.getLosingDialog()) {
if (which == DialogInterface.BUTTON_POSITIVE) {
// TODO: Polish the dialog.
// TODO: Add a method of obtaining the score from RenderView.
renderView.getStage().reset();
renderView.setDialogFlag(false);
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
PlayActivity.this.onBackPressed();
}
} else if dialog == renderView.getWinningDialog()) {
// etc...
} else if dialog == renderView.getPausingDialog()) {
// etc...
}
}
I can't guarantee that this will improve performance, but it will definitely make the garbage collector very happy :-)
I have an alert dialog with a single-choice list and two buttons: an OK button and a cancel button. The code below show how I implemented it.
private final Dialog createListFile(final String[] fileList) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Compare with:");
builder.setSingleChoiceItems(fileList, -1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Log.d(TAG,"The wrong button was tapped: " + fileList[whichButton]);
}
});
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {}
});
return builder.create();
}
My goal is to obtain the name of the selected radio button when the OK button is tapped. I tried to save the string in a variable, but inside an inner class it is possible to access only final variables. Is there a way to avoid using a final variable to store the selected radio button?
Using a final variable obviously won't work (since it can only be assigned once, at declaration time). So-called "global" variables are usually a code smell (especially when they become part of an Activity class, which is usually where AlertDialogs are created).
The cleaner solution is to cast the DialogInterface object to an AlertDialog and then call getListView().getCheckedItemPosition(). Like this:
new AlertDialog.Builder(this)
.setSingleChoiceItems(items, 0, null)
.setPositiveButton(R.string.ok_button_label, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition();
// Do something useful withe the position of the selected radio button
}
})
.show();
This has been answered just fine, but I keep finding this answer from Google and I wanted to share a non-anonymous class solution. I prefer reusable classes myself and may be helpful to others.
In this example, I'm using a DialogFragment implementation and retrieving a value via a callback method.
The callback method to get values from a Dialog can be done by creating a public interface
public interface OnDialogSelectorListener {
public void onSelectedOption(int selectedIndex);
}
Also the DialogFragment implements DialogInterface.OnClickListener which means you can register the class you've implemented as the OnClickListener for the DialogFragment that is being created.
For example
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle(R.string.select);
builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this);
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
return builder.create();
}
The line
builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this);
Creates a choice dialog with the options from a resource array stored in mResourceArray. This also preselects an option index from what is stored in mSelectedIndex and finally it sets this itself as the OnClickListener. (See full code at the end if this paragraph is a tad confusing)
Now, the OnClick method is where you grab the value that comes from the dialog
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case Dialog.BUTTON_NEGATIVE: // Cancel button selected, do nothing
dialog.cancel();
break;
case Dialog.BUTTON_POSITIVE: // OK button selected, send the data back
dialog.dismiss();
// message selected value to registered callbacks with the
// selected value.
mDialogSelectorCallback.onSelectedOption(mSelectedIndex);
break;
default: // choice item selected
// store the new selected value in the static variable
mSelectedIndex = which;
break;
}
}
What happens here is when an item is selected, it's stored in a variable. If the user clicks the Cancel button, no update is sent back and nothing changes. If the user clicks the OK button, it returns the value to the Activity that created it via the callback created.
As an example, here is how you would create the dialog from a FragmentActivity.
final SelectorDialog sd = SelectorDialog.newInstance(R.array.selector_array, preSelectedValue);
sd.show(getSupportFragmentManager(), TAG);
Here, the resource array _R.array.selector_array_ is an array of strings to show in the dialog and preSelectedValue is the index to select on open.
Finally, your FragmentActivity will implement OnDialogSelectorListener and will receive the callback message.
public class MyActivity extends FragmentActivity implements OnDialogSelectorListener {
// ....
public void onSelectedOption(int selectedIndex) {
// do something with the newly selected index
}
}
I hope this is helpful to someone, as it took me MANY attempts to understand it. A full implementation of this type of DialogFragment with a callback is here.
public class SelectorDialog extends DialogFragment implements OnClickListener {
static final String TAG = "SelectorDialog";
static int mResourceArray;
static int mSelectedIndex;
static OnDialogSelectorListener mDialogSelectorCallback;
public interface OnDialogSelectorListener {
public void onSelectedOption(int dialogId);
}
public static DialogSelectorDialog newInstance(int res, int selected) {
final DialogSelectorDialog dialog = new DialogSelectorDialog();
mResourceArray = res;
mSelectedIndex = selected;
return dialog;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mDialogSelectorCallback = (OnDialogSelectorListener)activity;
} catch (final ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnDialogSelectorListener");
}
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
builder.setTitle(R.string.select);
builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this);
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
return builder.create();
}
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case Dialog.BUTTON_NEGATIVE:
dialog.cancel();
break;
case Dialog.BUTTON_POSITIVE:
dialog.dismiss();
// message selected value to registered calbacks
mDialogSelectorCallback.onSelectedOption(mSelectedIndex);
break;
default: // choice selected click
mSelectedIndex = which;
break;
}
}
}
Question from a comment How to call this from a Fragment instead of an Activity.
First make a few changes to the DialogFragment.
Remove the onAttach event since that's not the easiest way in this scenario.
Add a new method to add a reference to the callback
public void setDialogSelectorListener (OnDialogSelectorListener listener) {
this.mListener = listener;
}
Implement the listener in your Fragment
public class MyFragment extends Fragment implements SelectorDialog.OnDialogSelectorListener {
// ....
public void onSelectedOption(int selectedIndex) {
// do something with the newly selected index
}
}
Now create a new instance and pass in a reference to the Fragment to use it.
final SelectorDialog sd = SelectorDialog.newInstance(R.array.selector_array, preSelectedValue);
// this is a reference to MyFragment
sd.setDialogSelectorListener(this);
// mActivity is just a reference to the activity attached to MyFragment
sd.show(this.mActivity.getSupportFragmentManager(), TAG);
final CharSequence[] choice = {"Choose from Gallery","Capture a photo"};
int from; //This must be declared as global !
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle("Upload Photo");
alert.setSingleChoiceItems(choice, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (choice[which] == "Choose from Gallery") {
from = 1;
} else if (choice[which] == "Capture a photo") {
from = 2;
}
}
});
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (from == 0) {
Toast.makeText(activity, "Select One Choice",
Toast.LENGTH_SHORT).show();
} else if (from == 1) {
// Your Code
} else if (from == 2) {
// Your Code
}
}
});
alert.show();
As others have pointed out, implementation 'com.google.android.material:material:1.0.0' it is more simply
Refere this material guide for more. https://material.io/develop/android/docs/getting-started/
CharSequence[] choices = {"Choice1", "Choice2", "Choice3"};
boolean[] choicesInitial = {false, true, false};
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(getContext())
.setTitle(title)
.setPositiveButton("Accept", null)
.setNeutralButton("Cancel", null)
.setMultiChoiceItems(choices, choicesInitial, new DialogInterface.OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
}
});
alertDialogBuilder.show();
Try this.
final String[] fonts = {"Small", "Medium", "Large", "Huge"};
AlertDialog.Builder builder = new AlertDialog.Builder(TopicDetails.this);
builder.setTitle("Select a text size");
builder.setItems(fonts, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if ("Small".equals(fonts[which])) {
Toast.makeText(MainActivity.this,"you nailed it", Toast.LENGTH_SHORT).show();
}
else if ("Medium".equals(fonts[which])) {
Toast.makeText(MainActivity.this,"you cracked it", Toast.LENGTH_SHORT).show();
}
else if ("Large".equals(fonts[which])){
Toast.makeText(MainActivity.this,"you hacked it", Toast.LENGTH_SHORT).show();
}
else if ("Huge".equals(fonts[which])){
Toast.makeText(MainActivity.this,"you digged it", Toast.LENGTH_SHORT).show();
}
// the user clicked on colors[which]
}
});
builder.show();