I'm having the following issue developing in android 2.2 (API 8):
I have a customized Dialog class like this:
public AuthDialog(final Context context, OnDismissListener dismissListener, OnCancelListener cancelListener) {
super(context);
setOnDismissListener(dismissListener);
setOnCancelListener(cancelListener);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.userpassdialog);
setTitle("Enter email and password");
setCancelable(true);
setCanceledOnTouchOutside(true);
authEmail = (EditText) findViewById(R.id.authEmail);
authPass = (EditText) findViewById(R.id.authPass);
alertMessage = (TextView) findViewById(R.id.auth_alert);
Button authButton = (Button) findViewById(R.id.authButton);
View.OnClickListener onClickListener = new View.OnClickListener() {
public void onClick(View v) {
if (checkCredentials())
dismiss();
else
showAlert();
}
};
authButton.setOnClickListener(onClickListener);
}
private void showAlert() {
alertMessage.setText("Wrong user/pass");
authEmail.setText(null);
authPass.setText(null);
}
private boolean checkCredentials() {
// Empty user/pass for now
boolean checkEmail = authEmail.getText().toString().equals("");
boolean checkPassword = authPass.getText().toString().equals("");
return checkEmail && checkPassword;
}
#Override
public void onBackPressed() {
cancel();
}
And I create a new AuthDialog like this:
private void authenticateThenAccept() {
OnDismissListener dismissListener = new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
accept();
}
};
OnCancelListener cancelListener = new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
cancel();
}
};
AuthDialog dialog = new AuthDialog(context, dismissListener, cancelListener);
dialog.show();
}
I'm using the debugger, and I see that when I cancel (using the back button or pressing outside the dialog) the app dismisses the dialog instead of cancelling.
Anybody has had this kind of issue with Dialogs?
Thanks in advanced.
onDismiss() is always fired when dialog closes. The documentation for setOnCancelListener() states: "This will only be invoked when the dialog is canceled, if the creator needs to know when it is dismissed in general, use setOnDismissListener", i.e. it's not either onCancel or onDismiss but both when a dialog is canceled. I agree though that it would have made more sense had that not been the case.
Assuming this dialog should be modal, make your dialog a new activity.
setCancelable(false) will prevent the back button from doing anything. Many developers just turn off the ability of the back button to close the dialog since it's unclear whether that is a cancel or ok action to the user.
Related
I am working on an App that has a DialogBuilder Class where I implemented all the Dialogs for the App in order to be able to call them in other Services or Activities; that works very well except in one Activity, where I tried everything to pass the context - it is not working; hence, I would be more than delighted for any hints or help on this, thanks!
The Dialog:
public static void bookingConfirmationDialog(Context mContext) {
if(mContext != null) {
final Dialog dialog = new Dialog(GoldbekStorageApp.getInstance(), 0);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setContentView(R.layout.new_booking_layout);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
TextView textView = dialog.findViewById(R.id.messageId);
textView.setText(GoldbekStorageApp.getInstance().messageId);
Button okButton = dialog.findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}
The call of the Dialog:
proceedButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
message.setType(type);
message.setFromId(fromID);
message.setToId(toID);
message.setTypeId(typeID);
message.setTime(time);
message.setTitle(title);
message.setReceiptNo(receiptNo);
message.setNote(note);
RestClient.putBookingOnPallet(basic,message,context);
DialogBuilder.bookingConfirmationDialog(context);
/* Intent activityChangeIntent = new Intent( NewProductActivity.this,
NewProductActivity.class);
NewProductActivity.this.startActivity(activityChangeIntent);*/
}
});
I may be missing something but you could override onAttach in the DialogFragment class instead of passing the context in through the constructor.
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
I am working on project, which simply validates through username and password.
I made some progress with using DialogFragments and AlertDialog. AlertDialog appears after starting the app over the mainactivity asking for username and password.
I must set the Alertdialog's setCanceledOnTouchOutside(false) and DialogFragment's setCancelable(false) because I don't want the users to dismiss it with pressing android's back button.
The problem is, after dismissing it programatically on successful login, if the activity becomes invisible and visible again , the Alertdialog's OnShowListener called, showing this AlertDialog again.
Can I somehow "detach" this AlertDialog from Activity? This popups also happen after unlocking the screen and getting back to activity which makes it very annoying...
Here is the code of interest:
MainActivity
public class MainActivity extends AppCompatActivity implements NoticeDialogFragment.NoticeDialogListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(GlobalInformations.getInstance().getUsername()==null){
shownoticeDialog();
}
}
public void shownoticeDialog(){
DialogFragment dialogFragment = new NoticeDialogFragment();
dialogFragment.show(getFragmentManager(), "NoticeDialogFragment");
}
#Override
public void onDismiss(DialogFragment dialog) {
//set the username on a TextView instance, etc...
}
NoticeDialogFragment extends DialogFragment
public class NoticeDialogFragment extends DialogFragment {
public interface NoticeDialogListener{
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
public void onDismiss(DialogFragment dialog);
}
NoticeDialogListener mListener;
static Activity activity = null;
//static String username;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
activity = (Activity) context;
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e){
throw new ClassCastException(activity.toString() + "must implement NoticeDialogListener");
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_signin, null);
final AutoCompleteTextView actv_username = (AutoCompleteTextView) view.findViewById(R.id.username);
final EditText password = (EditText) view.findViewById(R.id.password);
getavailableusernames(actv_username);
final AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(getContext(), R.style.AlertDialogCustom))
.setView(view)
.setTitle("Login")
.setPositiveButton("OK", null)
//.setNegativeButton("Cancel", null)
.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialogInterface) {
final Button button =((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String passw = password.getText().toString();
String user = actv_username.getText().toString();
try{
if(user.length()<4 || passw.length()<4){
Toast.makeText(getContext(), "Username/password too short", Toast.LENGTH_SHORT).show();
dialog.show();
}
else {
//login to account, if success dismiss.
login(user, passw,dialog);
}
} catch(Exception e){
}
// dialog.dismiss();
}
});
}
});
dialog.setCanceledOnTouchOutside(false);
// set the DialogFragment to make the dialog unable to dismiss with back button
// (because not working if called on the dialog directly)
this.setCancelable(false);
return dialog;
}
public void login(final String username, String password, final AlertDialog dialog){
boolean login_success = false;
//query the credentials
login_success = dosomesqlquery(username, password);
if(login_success){
dialog.dismiss();
}
}
//passing the handling to activity...
#Override
public void onDismiss(DialogInterface dialog) {
mListener.onDismiss(NoticeDialogFragment.this);
}
}
Thank you for your help and patience.
Well this is that kind of situation where I end up heading my desk continously.
The source of the problem was I called dialog.dismiss() which dismisses the dialog, BUT not the dialogfragment itself, so will never, ever dismissed, even if the dialog disappeared from screen. Placing this.dismiss() in NoticeDialogFragment's onDismiss or anywhere else after login succeded will let the application act as it should.
#Override
public void onDismiss(DialogInterface dialog) {
mListener.onDismiss(NoticeDialogFragment.this);
this.dismiss(); //will dismiss the DialogFragment. Yeeey!
}
Thank you for your time and answers as they helped me point out the real problem. I will modify the code based on your suggestions.
An easier way is to use a static variable in your activity using two steps.
Declare a global static boolean
private static boolean session = false;
Check if the boolean has changed and if not, set the boolean to true when the dialog is shown
public void shownoticeDialog(){
if(session)return;
DialogFragment dialogFragment = new NoticeDialogFragment();
dialogFragment.show(getFragmentManager(), "NoticeDialogFragment");
session = true;
}
Set the value when the activity goes background
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("authUser", GlobalInformations.getInstance().getUsername()==null)
}
and read it when it comes back
#Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState != null && savedInstanceState.containsKey("authUser")) {
boolean authUser = savedInstanceState.getBoolean("authUser", false);
if(authUser) {
//show or don't show dialog
}
}
}
Why doesn't dialog dismiss on the first click (but shows Toast) ?
On the second click it dismisses (Toast is shown again).
private void networkDialog(){
final Dialog dialog = new Dialog(EnterActivity.this, android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(R.layout.custom_dialog);
Button nobutton = (Button) dialog.findViewById(R.id.dialogButLeft);
nobutton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
Toast.makeText(getApplicationContext(), "DIALOG", Toast.LENGTH_LONG).show();
}
});
dialog.show();
}
Try this way .Let me inform .I hope it will help you.
private void networkDialog()
{
final Dialog dialog = new Dialog(EnterActivity.this, android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(R.layout.custom_dialog);
Button nobutton = (Button) dialog.findViewById(R.id.dialogButLeft);
nobutton.setOnClickListener(this);
dialog.show();
}
Then Use onClick switch Statement
public void onClick(View view)
{
switch (view.getId())
{
case R.id.dialogButLeft:
Toast.makeText(getApplicationContext(), "DIALOG", Toast.LENGTH_LONG).show();
dialog.dismiss();
break;
}
}
A bit late but a colleague had the same issue and referred to this, are you absolutely sure that you're not creating two dialogs by calling networkDialog() twice?
Add some unique text to the dialog that will be visible to you when it's displayed like System.currentTimeMillis(), that way you can see if it's called twice because the text is different.
Or add logging / run in debug
Make your Button also final like this:
private void networkDialog(){
final Dialog dialog = new Dialog(EnterActivity.this, android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(R.layout.custom_dialog);
final Button nobutton = (Button) dialog.findViewById(R.id.dialogButLeft);
nobutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
Toast.makeText(getApplicationContext(), "DIALOG", Toast.LENGTH_LONG).show();
}
});
dialog.show();
}
it's working for me in my app like this:
// Initialize variables
final Dialog passwordDialog = new Dialog(BPMActivity.this,R.style.CustomDialogStyle);
passwordDialog.setContentView(R.layout.password_view);
final Button btnCancel=(Button) passwordDialog.findViewById(R.id.btn_cancel);
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
passwordDialog.dismiss();
}
});
passwordDialog.show();
I don't know if this is still relevant to the OP. But I've been banging my head against the wall for quite some time trying to figure this one out. It appears to happen in later (5-6+) Android versions and did not occur on a 4.4.2 device which I have. The solution I've found is to setFocusableInTouchMode of the Button to false:
button.setFocusableInTouchMode(false)
This answer gave me the idea:
I have to click the button twice for it to work
I have a custom preference, TimePreference, which extends DialogPreference. It has a custom dialog resource, which looks like this
The source is
#Override
protected void onBindDialogView(View v){
super.onBindDialogView(v);
v.findViewById(R.id.butCancel).setOnClickListener(onClickL);
v.findViewById(R.id.butNow).setOnClickListener(onClickL);
v.findViewById(R.id.butOK).setOnClickListener(onClickL);
//....
}
//...
private final View.OnClickListener onClickL = new View.OnClickListener(){
#Override
public void onClick(View v) {
Log.d(lTag, v + " clicked");
switch (v.getId()) {
case R.id.butOK: saveToSP(false);break;
case R.id.butNow: saveToSP(true);
}
try {
getDialog().dismiss(); //may throw null pointer
} catch (Exception e) { Log.w(lTag, "Exc #onClickL", e); }
}
};
//...
I found a bug where, if you clicked the same preference really fast twice (at the preference screen) two dialogs would open. You could close the first one but, when you would try to close the second, the app would crash. It was a NullPointerException, so I enclosed it in a try-catch block. Now, the exception is caught, but the buttons do not close the dialog. Notice that, by clicking back, it does close.
How can I close the second dialog (possibly by simulating the behaviour of the back button?) ? Note, I want the API level below 10.
Okay, I found a soultion. I have a static boolean, which shows if there is an open dialog.
private static boolean isAnyDialogOpen = false;
On dialog bind, I set it to true,
And after I close the dialog, I set it to false.
Turned out that even this was problematic, but the solution was easier
#Override
protected void onClick() {
if (isAnyDialogOpen)
Log.i(lTag, "there is a dialog already");
else {
isAnyDialogOpen = true;
super.onClick();
}
}
#Override
public void onDismiss(DialogInterface dialog) {
Log.d(lTag, "dismiss, dialog= "+dialog);
isAnyDialogOpen = false;
if (dialog != null) super.onDismiss(dialog);
}
I have popup window class like the following.
public class Popup extends PopupWindow {
Context context;
EditText et_bankname, et_banknumber;
String bank_name, account_number;
public Popup(Context ctx) {
super(ctx);
context = ctx;
setContentView(LayoutInflater.from(context).inflate(R.layout.bank_details, null));
setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
View popupView = getContentView();
setFocusable(true);
Button btn_close = (Button) popupView.findViewById(R.id.popupClose);
Button btn_submit = (Button) popupView.findViewById(R.id.popupSave);
et_bankname = (EditText) popupView.findViewById(R.id.bank_name);
et_banknumber = (EditText) popupView.findViewById(R.id.bankacc_no);
btn_submit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
bank_name = et_bankname.getText().toString();
account_number = et_banknumber.getText().toString();
if (!bank_name.equals("") && !account_number.equals("")) {
Toast t1 = Toast.makeText(context,bank_name + " "+account_number , Toast.LENGTH_SHORT);
t1.setGravity(Gravity.TOP, 0, 100);
t1.show();
dismiss();
} else {
Toast t1 = Toast.makeText(context,
"Please provide valid details", Toast.LENGTH_SHORT);
t1.setGravity(Gravity.TOP, 0, 100);
t1.show();
}
}
});
}
public void show(View v) {
showAtLocation(v, Gravity.CENTER, 0, 0);
}
}
I will access this popup in my activity by
Popup popup = new Popup(getBaseContext());
popup.show(arg1);
This works perfectly. But I want to know when this popup window gets dismissed. for this purpose now I am using Thread concept like following.
if (isPopupShowing) {
Thread thread = new Thread() {
#Override
public void run() {
while (isPopupShowing) {
if (!popup.isShowing()) {
isPopupShowing = false;
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
loadDSP(type);
}
});
}
}
}
};
thread.start();
}
But this thread will run continuesly until the popup window gets dismissed. So I feel it is better to replace this solution by any other way.
What I want?
Just intimate to my activity like "popup is closed" when popup is dismissed.
Why I am use this way?
I will use this popup window in three activty. That is why I am create a separate class for popup window.
Any help will be highly appriciated.
Thank you.
PopupWindow already has its own dismiss listener, just use it as follows
Popup popup = new Popup(getBaseContext());
popup.show(arg1);
Change that to
Popup popup = new Popup(getBaseContext());
popup.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
// Do your action
}
});
popup.show(arg1);
EDIT
I hadn't noticed you were extending a PopupWindow, which already has this implemented as shown in #Jayabal's answer. Anyway this is how you would do it if the PopupWindow didn't already have it's own onDismissListener.
Simply create your own OnDismissListener Interface.
public interface onDismissListener{
public void onDismiss();
}
Add a reference to a Listener in the PopUp class and a setter.
OnDismissListener listener;
public void setOnDismissListener(OnDismissListener listener){
this.listener = listener;
}
Then in your Activity
Popup popup = new Popup(getBaseContext());
popup.setOnDismissListener(new OnDismissListener(){
public void onDismiss(){
//do what you need to here
}
});
popup.show(arg1);
This pattern should be familiar to you, its used everywhere in Android.