mSomeFragment = new SomeFragment();
mSomeFragment.show(getFragmentManager(), "some");
The Fragment shows fine.
mSomeFragment = new SomeFragment();
mSomeFragment.show(getFragmentManager(), "some");
mSomeFragment.onDismiss(new DialogInterface() {
#Override
public void cancel() {
//
}
#Override
public void dismiss() {
//
}
});
But when I set onDismiss, this doesn't work (the Fragment doesn't shows). I wanna do some operations when the dialog dismisses.
Could you tell me why??
Calling onDismiss actually calls this code
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
which dismisses the dialog. If you want to listen for events on the dialog use onOptionsItemSelected()
Related
I have an app with a single activity and two fragments. Fragment B is added(addedToBackStack) on Top of Fragment A. In Fragment B, I am showing a dialog, going back to Fragment A and then dismissing the dialog. If getActivity()!=null check is removed inside the handler, the code works fine. But getActivity() is null inside handler. Why is getActivity() null inside handler in the following piece of code?
private void showDialog(final Dialog dialog) {
dialog.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (getActivity()!=null && !getActivity().isFinishing()) {
dialog.dismiss();
}
}
}, 1000);
if (getActivity() != null && !getActivity().isFinishing())
getActivity().onBackPressed();
}
getActivity() is null because after getActivity().onBackPressed(); call your fragment will get detached from the Activity. So inside handler it will be always null because its getting called with a delay.
If you want to dismiss dialog after one second and also move back to previous fragment then you should move onBackPressed inside the run method. i have replaced the null check with isAdded().
private void showDialog(final Dialog dialog) {
dialog.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (isAdded()) {
dialog.dismiss();
getActivity().onBackPressed();
}
}
}, 1000);
}
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
}
}
}
I'm trying to perform an action in one fragment, then move to the previous fragment and show a snackbar with a message, confirming the action from the first fragment. However, I'm creating and showing the snackbar in the first fragment (the one I'm moving from), and the snackbar does not appear in the fragment I'm changing to, probably because it's shown in the fragment I'm moving from.
I'm executing the code inside an alertdialog:
builder.setPositiveButton(positiveText, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dbHandler.deleteExercise(exercise.getId());
// Making the snackbar here did not work, either.
getFragmentManager().popBackStack();
Snackbar snack = Snackbar.make(mainLayout, "Exercise deleted", Snackbar.LENGTH_SHORT);
snack.show();
}
});
Any idea how I could go about achieving this?
Thanks!
EDIT:
I made this incredibly crude drawing of the flow to make it clearer what I'm trying to achieve.
I ended up implementing messaging between Fragments via the main Activity and checking for messages in the fragment's onResume() method:
MainActivity:
private String fragmentTransactionMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Snip
// Initialize fragment transaction message
fragmentTransactionMessage = null;
// Snip
}
// Three methods used to send information (text) between fragments
public void setFragmentTransactionMessage(String message) {
this.fragmentTransactionMessage = message;
}
public String getFragmentTransactionMessage() {
return fragmentTransactionMessage;
}
public void resetFragmentTransactionMessage() {
this.fragmentTransactionMessage = null;
}
Fragment 2:
// Remove exercise from database
dbHandler.deleteExercise(exercise.getId());
// Update message in main activity
((MainActivity)getActivity()).setFragmentTransactionMessage("Item deleted");
// Move to previous fragment
getFragmentManager().popBackStack();
Fragment 1:
#Override
public void onResume() {
super.onResume();
// Check for messages in main activity
String message = ((MainActivity)getActivity()).getFragmentTransactionMessage();
// If any, display as snackbar
if(message != null) {
Snackbar snack = Snackbar.make(mainLayout, message, Snackbar.LENGTH_SHORT);
snack.show();
// Reset message in activity
((MainActivity)getActivity()).resetFragmentTransactionMessage();
}
}
Another suggestion is to wrap getFragmentManager().popBackStack(); in a method which takes a Runnable Obj which will run after a chosen delay
For Example:
public void goBack(Runnable runAfterBack, long delay) {
mFragmentActivity.onBackPressed();
if (runAfterBack != null) {
(new Handler(Looper.getMainLooper())).postDelayed(runAfterBack, delay);
}
}
Usage:
goBack(new Runnable() {
#Override
public void run() {
Toast.makeText(mActivity, "STRING", Toast.LENGTH_SHORT).show();}
}, 1500);
I have a dialog fragment with a simple indeterminate progress bar in the centre, which i use to show network activity:
public class NativeLoadingDialogFragment extends DialogFragment {
public NativeLoadingDialogFragment() {
// Blank
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity(), android.R.style.Theme_Dialog);
ProgressBar indeterminateProgressBar = new ProgressBar(getActivity());
indeterminateProgressBar.setIndeterminate(true);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
dialog.setContentView(indeterminateProgressBar);
dialog.getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
return dialog;
}
public boolean isShowing() {
return getDialog() != null;
}
}
I have used the dialog fragment throughout my app with no issues, it shows up without issue in lots of places when i call dialog.show(getFragmentManager, null), however when I try to call it in onResume of my settings activity it does not show!
I have an activity for settings, which launches the system settings to change the language of the phone. Once the user changes the language and my activity resumes I detect if the language has changed and do a network call:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mLoading = new NativeLoadingDialogFragment();
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(EXTRA_LANGUAGE)) {
String language = savedInstanceState.getString(EXTRA_LANGUAGE);
String currentLanguage = AppUtils.getDefaultLanguageCode(
SmartBankConstant.DEFAULT_LANGUAGE,
SmartBankConstant.SUPPORTED_LANGUAGES);
if (!language.equals(currentLanguage)) {
updateLanguage(Language.stringToLanguage(currentLanguage));
}
}
}
}
private void updateLanguage(Language newLanguage) {
....
getSpiceManager().execute(new SetLanguageRequest(newLanguage),
new SetLanguageRequestListener(this));
mLoading.show(getFragmentManager(), null);
getFragmentManager().executePendingTransactions();
}
The code definitely runs but no dialog appears! If the network call fails I have a retry option that calls the updateLanguage(Language newLanguage) method again, and the dialog actually appears that time! What am I doing wrong?
Try with this approach. It checks if the dialog is already displayed, otherwise it shows it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mLoading = new NativeLoadingDialogFragment();
if (savedInstanceState != null) {
...
}
mLoading.show(getFragmentManager(), null);
}
private void updateLanguage(Language newLanguage) {
...
if (mLoading != null && !mLoading.isVisible()) {
mLoading.show(getFragmentManager(), null);
getFragmentManager().executePendingTransactions();
}
}
I don't know why, but running fragment transaction in the next loop helped to solve this issue.
new Handler().post(new Runnable() {
#Override public void run() {
// for some reason this must be called in the next loop
dialogFragment.show(getSupportFragmentManager(), tag);
}
});
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.