Java: How to reuse listeners - java

I would like to reuse an AlertBuilder and therefore put its creation in an own method. Something like this:
private boolean askToDiscardChanges() {
final boolean result = false;
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
result = true;
break;
case DialogInterface.BUTTON_NEGATIVE:
result = false;
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(NewShootingActivity.this);
builder.setMessage(getResources().getString(R.string.msgDiscardChanges)).setPositiveButton(getResources().getString(R.string.lblYes), dialogClickListener)
.setNegativeButton(getResources().getString(R.string.lblNo), dialogClickListener).show();
return result;
}
Unfortunately, this does not work but I hope it helps to understand my issue. Is it possible to return the result of a listener? How?
Thanks

A listener is a callback function. It will be called at some later point in time, possibly far in the future- or even possibly never. So no, it can't return a value, because we don't know what to return yet. If you want to run some code based on a callback being called, you need to put that code in the callback.

Related

My Method always return 0 ignoring the condition

I have read some related questions like this and this but there the problem is int can't hold much bigger value. In my case its not that.
I'm calling the below method in OnClick of button but it return always 0
public int showRadioAlertDialog(final Button button, String title,
final List<String> list, int selectedIndex) {
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(title);
builder.setCancelable(false);
builder.setSingleChoiceItems(list.toArray(new String[list.size()]),
selectedIndex, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (which > -1) {
position = which;
}
}
});
builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
printLog("List position = " + list.get(position));
if (position > -1) {
button.setHint(list.get(position));
}
}
});
builder.setNegativeButton("Cancel", null);
AlertDialog dialog = builder.create();
dialog.show();
if (position > -1) {
return position;
} else {
return -1;
}
}
position is a global variable.
What I'm expecting is it should return -1 or the index of selected position.
First thing that I noticed is it return value before user select an
item from single choice, it should not return anything before user
select an item.
Second if it return before selection the I have a check at the end
so it should be -1 why 0.
Please explain a bit why its 0. Any effort would be appreciated.
You call this:
if (position > -1) {
return position;
} else {
return -1;
}
After setting the onClickListeners. The thing is that the onClickListeners are invoked from a different thread when the event happens, meaning by the time position is set, the value has been returned already.
You can't get proper return methods when you use onClickListeners, as they are called as inner classes (or a method if you extend onCLickListener). Use callback methods instead (the following is pseudocode and isn't valid. Don't copy-paste and expect it to work):
... onClick(){
callback(position);
}
...
void callback(position){
do whatever with the variable
}
If you define integer variable as global, default value is automatically given and the value is 0. In your case, you have conditional code that is after show() method call. This means will execute the code immediately after calling show() method. Since 0 > -1 hence you will always get 0. Hope this helps you. If you want to add position after clicking the dialogue then in call back method of dialogue you need to set the value to that variable position explicitly. Return will not work. Because by the time you click the dialogue button value has already been returned. And why is o returning I have already mentioned the begining of my answer.

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!
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.

Android DialogFragment newInstance optional parameters

I've been following the official android developer docu and this one for the use of DialogFragment inside my project. so far so good, since I have to pass data to the DialogFragment for it to create a multichoice list, I call the DialogFragment from inside my MainActivity via the newInstance method (passing the items) and I am getting a correct result. Now, I would like to pass another argument, also data for the DialogFragment but it has to be optional since I dont need to pass it all the time. Is there a way for me to achieve this?
EDIT:
so I took the Advice from the comments below and created a setter and passed the items i wished to pass to the DiagramFragment. It worked just fine, sadly it didn't help me solve my problem. The reason I wanted to pass the second data is that I thought, if the user opens the DialogFragment and makes a selection and after that reopens the DialogFragment his last choice is gone. I wanted to check the checkboxes he already had checked programmatically, by passing the checked once back to the DialogFragment and then setting the right indexes back into mSelectedItems - but even tho the indexes are set correctly the checkboxes stay unchecked.. is there a workaround?
static MyDialogFragment newInstance(int num) {
MyDialogFragment f = new MyDialogFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
...
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mSelectedItems = new ArrayList(); // Where we track the selected items
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Set the dialog title
builder.setTitle(R.string.pick_toppings)
// Specify the list array, the items to be selected by default (null for none),
// and the listener through which to receive callbacks when items are selected
.setMultiChoiceItems(R.array.toppings, null,
new DialogInterface.OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int which,
boolean isChecked) {
if (isChecked) {
// If the user checked the item, add it to the selected items
mSelectedItems.add(which);
} else if (mSelectedItems.contains(which)) {
// Else, if the item is already in the array, remove it
mSelectedItems.remove(Integer.valueOf(which));
}
}
})
// Set the action buttons
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
// User clicked OK, so save the mSelectedItems results somewhere
// or return them to the component that opened the dialog
...
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
...
}
});
return builder.create();
}
an optional parameter can be done like this:
static MyDialogFragment newInstance() {
return newInstance(-1);
}
static MyDialogFragment newInstance(int num) {
MyDialogFragment f = new MyDialogFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
You can call newInstance() if you have no number or newInstance(300) if you have.
On the other side:
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int num = getArguments().getInt("num");
if(num == -1) {
// no extra number
} else {
// do something with the extra number
}
...
Alternatively instead of using -1 you could not add the Int at all and just check for the default value (I think its 0 in the API docs)
I got it, it was already answered - funny I didn't find it when I googled..
There are easiest ways of doing what you want but let's take this approach:
As you have noticed, the setMultiChoiceItems() method receives a String[] as the items of your DialogFragment and a boolean [] to define if they are checked or not. We are going to use this array to persist our choices. This array must have the same length as the items array and will be initially set to false.
So all I had to do was create a boolean[] itemsChecked and set the correct indexes to true, to re-check the right checkboxes..
Original Question Persist AlertDialog checked options - all credit to #joao2fast4u

How to return a value from dialog in separate class

I want to create a function that shows a dialog with 2 buttons on screen and return 1 if user pressed OK and 0 if user pressed Cancel.
public class CDlg {
static int ShowConfirm(String caption, String msg, Context context) {
int rez;
AlertDialog.Builder delAllDialog = new AlertDialog.Builder(context);
delAllDialog.setTitle(caption);
TextView dialogTxt_id = new TextView(context);
LayoutParams dialogTxt_idLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
dialogTxt_id.setLayoutParams(dialogTxt_idLayoutParams);
dialogTxt_id.setText(msg);
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(dialogTxt_id);
delAllDialog.setView(layout);
delAllDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
rez = 1;
}
});
delAllDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
rez = 0;
}
});
delAllDialog.show();
return rez;
}
}
I am now shure that I am doing right because I do not know how to pass a result from unner class to outer one. There is a error message
Cannot refer to a non-final variable rez inside an inner class defined in a different method
So as a result I want to use that function something like this:
if (CDlg.ShowConfirm("User confirmation","Delete?",this)==1){
...
}
You can't do this like that. ShowConfirm can only show the dialog. When the user clicks either the OK or Cancel button, only then you can execute what you want:
public class CDlg {
void ShowConfirm(String caption, String msg) {
AlertDialog.Builder delAllDialog = new AlertDialog.Builder(this);
delAllDialog.setTitle(caption);
TextView dialogTxt_id = new TextView(this);
LayoutParams dialogTxt_idLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
dialogTxt_id.setLayoutParams(dialogTxt_idLayoutParams);
dialogTxt_id.setText(msg);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(dialogTxt_id);
delAllDialog.setView(layout);
delAllDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
handleButtonClick(1);
}
});
delAllDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
handleButtonClick(2);
}
});
delAllDialog.show();
}
void handleButtonClick(int rez) {
switch(rez) {
case 1: ..... break;
case 2: ..... break;
.....
}
}
}
The if (CDlg.ShowConfirm("User confirmation","Delete?",this)==1) statement is useless in Android here, since the ShowConfirm will not wait until the user presses a button.
Instead just call ShowConfirm("User confirmation","Delete?"); an implement the appropriate code in the onClicks.
If you want to code in the spirit of Android, you should actually use startActivityForResult. Look at the linked answer for details how it should work. (here is the documentation)
Define a static variable in the class you want, for example I will define in MyAuxiliaryClass.java:
public static USER_DECISION = -1;
Whenever you choose an option, then you do the following:
if (//Desicion == OK) {
MyAuxiliaryClass.USER_DECISION = 1;
} else (//Decision == NOT OK){
MyAuxiliaryClass.USER_DECISION = 2;
}
Since you are changing this static variable, then you can get the value 1 or 2 in another class. Hope it helps. Best regards.
Make rez an attribute instead of a local variable. As your method is static, the attribute should be too. This means moving the definition outside the method.
public class CDlg {
static int rez;
static int ShowConfirm(String caption, String msg, Context context) {
...
In the inner classes, you need to refer to the CDlg class
public void onClick(DialogInterface arg0, int arg1) {
CDlg.rez = 1;
}
As a side note, it is strange that you use an static method for this. One of the mistakes of the people new to Java/OOP is to abuse static code, that feels more like C was. Maybe you want to reconsider your code.

how to quit a loop or onClick(android)?

Got a problem here on exiting onclick.
The program uses shared preferences to get inputs,
and if String name = "User", the program wouldn't let the user click this button and just display an alert dialog box.
This is my code below:
public void onClick(View v) {
name = shared.getString("sharedname", "User");
gender = shared.getInt("sharedgender", 0);
age = shared.getInt("sharedage", 0);
weight =shared.getInt("sharedweight", 0);
height = shared.getInt("sharedheight", 0);
if(name=="User")
{
new AlertDialog.Builder(cont)
.setMessage("Please input your information first")
.setNeutralButton("OK", null).show();
break;//error
}
//code code code, rest of the code to be cancelle
use equals(Object) method instead of == operator
if(name.equals("User"))
{
new AlertDialog.Builder(cont)
.setMessage("Please input your information first")
.setNeutralButton("OK", null).show();
return ;
}
The equals() method of java.lang.Object acts the same as the == operator; that is, it tests for object identity rather than object equality. The implicit contract of the equals() method, however, is that it tests for equality rather than identity. Thus most classes will override equals() with a version that does field by field comparisons before deciding whether to return true or false.
use :
if(name.equalsIgnoreCase("User")){
// your code
return;
}
AlertDialog.Builder builder = new Builder(ValueSelling.this);
AlertDialog alertDialog = builder.create();
alertDialog.setTitle(getResources().getString(R.string.termsTitle));
alertDialog.setMessage(getResources().getString(R.string.terms));
alertDialog.setCancelable(false);
alertDialog.setButton("Okay", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}});
alertDialog.setButton2("Cancel", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
}});
alertDialog.show();
Instead of using break, simply use a return; statement.

Categories