android.view.WindowManager$BadTokenException error while creating dialog box - java

I am trying to create a Dialog Box from an Non activity Class.
This is my Code
public static void ShowDialogBox(final Context con, final Listener list) {
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(con);
dlgAlert.setMessage("TEXT");
dlgAlert.setTitle("TEXT");
dlgAlert.setPositiveButton("TEXT"),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show(); // THIS LINE GIVES ME AN ERROR
}
This is the error which I am getting
android.view.WindowManager$BadTokenException: at
android.view.ViewRootImpl.setView (ViewRootImpl.java:574) at
android.view.WindowManagerGlobal.addView
(WindowManagerGlobal.java:282) at
android.view.WindowManagerImpl.addView (WindowManagerImpl.java:85)
at android.app.Dialog.show (Dialog.java:298) at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS.onBackPressed
(Class.java:95) at android.app.Activity.onKeyUp
(Activity.java:2465) at android.view.KeyEvent.dispatch
(KeyEvent.java:2646) at android.app.Activity.dispatchKeyEvent
(Activity.java:2716) at
android.support.v7.internal.view.WindowCallbackWrapper.dispatchKeyEvent
(WindowCallbackWrapper.java:50) at
android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent
(AppCompatDelegateImplBase.java:224) at
com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent
(PhoneWindow.java:2280) at
android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent
(ViewRootImpl.java:4038) at
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess
(ViewRootImpl.java:4000) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3698) at
android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$AsyncInputStage.apply
(ViewRootImpl.java:3755) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$InputStage.deliver
(ViewRootImpl.java:3562) at
android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3731) at
android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent
(ViewRootImpl.java:3892) at
android.view.inputmethod.InputMethodManager$PendingEvent.run
(InputMethodManager.java:2208) at
android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback
(InputMethodManager.java:1849) at
android.view.inputmethod.InputMethodManager.finishedInputEvent
(InputMethodManager.java:1840) at
android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished
(InputMethodManager.java:2185) at
android.view.InputEventSender.dispatchInputEventFinished
(InputEventSender.java:141) at
android.os.MessageQueue.nativePollOnce (Native Method) at
android.os.MessageQueue.next (MessageQueue.java:143) at
android.os.Looper.loop (Looper.java:122) at
android.app.ActivityThread.main (ActivityThread.java:5254) at
java.lang.reflect.Method.invoke (Native Method) at
java.lang.reflect.Method.invoke (Method.java:372) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main
(ZygoteInit.java:697)
Here is the scenario of the user
Activity A -->Opens Activity B-->User presses Back button in Activity B--> On Back button pressed a listener is sent to Activity A --> And then the Dialog Box shown is called.

The issue you are having with the attempt to build your AlertDialog in a separate class is you are passing the AlertDialog the Context of your Activity. You get the error because the AlertDialog requires the WindowManager from the Activity which has the layout--not the Context. This is because Activit extends Context... not the other way around.
In order to make your code work you need to provide the AlertDialog.Builder access to the Activity. So change your code to something like this:
public class TestDialog {
private static final String TAG = TestDialog.class.getSimpleName();
Activity mActivity;
public TestDialog(Activity activity){
mActivity = activity;
}
public void showDialog(){
AlertDialog.Builder b = new AlertDialog.Builder(mActivity);
b.setTitle("Title");
b.setMessage("message");
b.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "showDialog : onClick");
}
});
b.create().show();
}
}
Now you can call the AlertDialog from an Activity lets say in this case MainActivity like this:
TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();
I have not tried this from a Fragment, so I do not know whether this works from a Fragment or whether you will continue to have issues with certain devices. For those reasons, I (and Google!) still strongly suggest that you use the DialogFragment instead, because is has been especially designed for this scenario. Take a look at the Google Docs.:
https://developer.android.com/guide/topics/ui/dialogs

I generally prefer using DialogFragment instead of what you attempted in order to cut down on repetition. Here is an example of a DialogFragment with a custom layout which I have called R.layout.fragment_alert_dialog:
public class AlertDialogFragment extends DialogFragment {
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
private String title;
private String message;
boolean endSuccess = false;
private AlertFinishedDialogListener mListener;
public AlertDialogFragment() {
}
public static AlertDialogFragment newInstance(String title, String message) {
AlertDialogFragment fragment = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
title = getArguments().getString(ARG_TITLE);
message = getArguments().getString(ARG_MESSAGE);
}
}
#Override
public Dialog onCreateDialog(Bundle saveIntsanceState){
final Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fragment_alert_dialog, null, false);
final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);
titleView.setText(title);
messView.setText(message);
builder.setView(rootView)
// .setTitle(title)
.setPositiveButton(R.string.ok_button_dialog_title, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
endSuccess = true;
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
mListener.onAlertFinishedDialog();
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
}
catch (Exception ex){
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface AlertFinishedDialogListener {
void onAlertFinishedDialog();
}
}
It incorporates a Listener just in case you need to be notified when the DialogFragment is completed.
First you need to implement the callback:
implements AlertDialogFragment.AlertFinishedDialogListener{
In order to call the AlertDialogFragment you do this from your Activity (also Fragment if necessary).
private void startAlertDialogFragment(String title, String mess){
AlertDialogFragment alert = AlertDialogFragment.newInstance(title, mess);
alert.show(getFragmentManager(), "alertDialogFragment132");
}
#Override
public void onAlertFinishedDialog() {
Log.e(TAG, "onAlertFinishedDialog");
}

Problem
You can show dialogs from activity context only. except TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY, which is not recommended if your app does not show emergency notifications to user.
Solution
If you have activity context available then you can show dialog from any class like service, broadcast receiver, or even any class you imagine.
Here is my workaround that can show dialog from any class like i said.
Here is a snippet what i do to show dialog from any class. (Could it
be more simpler!)
import android.app.Dialog;
import android.content.DialogInterface;
public class SampleClass {
void anyMethod() {
Dialog dialog = ApplicationContext.getInstance().showDialog("title", "yourMessage", "Cancel", "Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 1 clicked
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 2 clicked
}
});
}
}
Now you will implement to make this work.
1. make application class which you will register in android manifest application tag
<application
android:name=".ApplicationContext"
...
>
...
</application>
2. In this application class you will hold live activity object. that will further useful for showing dialog.
ApplicationContext.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;
public class ApplicationContext extends Application {
private static ApplicationContext mInstance;
private Activity liveActivity;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
#Override
public void onTerminate() {
super.onTerminate();
mInstance = null;
}
public static synchronized ApplicationContext getInstance() {
return mInstance;
}
public Activity getLiveActivity() {
return liveActivity;
}
public void setLiveActivity(Activity liveActivity) {
this.liveActivity = liveActivity;
}
/*
* Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
*/
public AlertDialog showDialog(String title, String msg,
String btn1, String btn2,
DialogInterface.OnClickListener listener1,
DialogInterface.OnClickListener listener2) {
if (liveActivity == null) return null;
AlertDialog.Builder builder = new AlertDialog.Builder(liveActivity)
.setTitle(title)
.setMessage(msg)
.setCancelable(false)
.setPositiveButton(btn1, listener1);
if (btn2 != null)
builder.setNegativeButton(btn2, listener2);
AlertDialog alert = builder.create();
alert.show();
return alert;
}
}
Just one more step
3. You will extend all your activity by this base activity class (You can edit your base activity if you already have one.)
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
#Override
protected void onResume() {
super.onResume();
ApplicationContext.getInstance().setLiveActivity(this);
}
#Override
protected void onPause() {
super.onPause();
ApplicationContext.getInstance().setLiveActivity(null);
}
}
Here you go !!!

Related

IllegalStateException: Fragment FiltroOpcao not attached to a context.- Android Error

I'm trying get item selected from user to fragment formulary on my Android app, following the google documentation this is possible using this methods from the library, i tried implement this methods and your Interface in my DialogFragment and get it on my fragment formulary, but, the error is returned when i click on the button necessary to open Dialog Fragment.
This is my Dialog Fragment class:
public class FiltroOpcao extends DialogFragment {
OnFiltroEscolhido listener;
private final String[] filtroAnuncio = getResources().getStringArray(R.array.filtro_array);
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
listener = (OnFiltroEscolhido) getTargetFragment();
}catch(ClassCastException e){
throw new ClassCastException(context.toString()+"Deve ser implementado");
}
}
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Filtrar por:")
.setItems(R.array.filtro_array, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
listener.pegarFiltro(filtroAnuncio[which]);
}
});
return builder.create();
}
public interface OnFiltroEscolhido{
void pegarFiltro (String escolha);
}
}
And it is where i called the DialogFragment and the crash happens on my VendaFragment fragment class
public void onClick(View v) {
FiltroOpcao filtroOpcao = new FiltroOpcao();
filtroOpcao.setTargetFragment(VendaFragment.this, 1);
filtroOpcao.show(VendaFragment.this.getChildFragmentManager(), "FiltroOpcao");
}
private final String[] filtroAnuncio = getResources().getStringArray(R.array.filtro_array);
Probably, getResources() is the problem because you are using it before the fragment was attached.
Try to move the initialization of filtroAnuncio to onCreateDialog()
private String[] filtroAnuncio;
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
filtroAnuncio = getResources().getStringArray(R.array.filtro_array);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Filtrar por:")
.setItems(R.array.filtro_array, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
listener.pegarFiltro(filtroAnuncio[which]);
}
});
return builder.create();
}

Setting a listener in Activity for DialogFragment

I am trying to implement a listener in my Activity on my DialogFragment( which has 3 numberPicker widget elements) which would be used to set values in textViews of the Activity and I don't want to make this Fragment class an inner class of Activity and set the textview in OnClickListener of the OK button as I will have to make my view static in that case which is not desirable. I know there is a listener onValueChange of the NumberPicker class, but how do I set a listener which gets values from the 3 picker elements. Any help to implement such a listener in the activity would be appreciated.
public class PickerDialog extends DialogFragment {
NumberPicker numberPicker;
NumberPicker numberPicker2;
NumberPicker numberPicker3;
public static PickerDialog newInstance() {
PickerDialog frag = new PickerDialog ();
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View child = getActivity().getLayoutInflater().inflate(R.layout.dialog, null);
numberPicker = child.findViewById(R.id.numberPicker1);
numberPicker2 = child.findViewById(R.id.numberPicker2);
numberPicker3 = child.findViewById(R.id.numberPicker3);
numberPicker.setMinValue(0);
numberPicker.setMaxValue(59);
numberPicker3.setMinValue(0);
numberPicker3.setMaxValue(59);
numberPicker2.setMinValue(0);
numberPicker2.setMaxValue(59);
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(getActivity(), R.style.Theme_Material_Dialog_Alert);
builder.setTitle("Choose Value");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
builder.setView(child);
return builder.create();
}
}
You can create a Listener interface that is implemented in your Activity and used in DialogFragment through a reference to the Activity. Something like:
public class MyActivity extends Activity implements NumberPickerListener {
...
#Override
public void onValuesPicked(int first, int second, int third) {
//Do work here.
}
...
}
The interface:
interface NumberPickerLisener {
void onValuesPicked(int first, int second, int third);
}
In your Fragment:
public class PickerDialog extends DialogFragment {
NumberPickerListener listener;
...
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View child = getActivity().getLayoutInflater().inflate(R.layout.dialog, null);
listener = (MyActivity)getActivity();
...
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
listener.onValuesPicked(numberPicker.getValue(), numberPicker2.getValue(), numberPicker3.getValue());
dismiss();
}
});
...
}
}

Create Custom AlertDialog Builder and Change Font of Title & Message

I have created a Custom AlertDialog Builder and I need to change font of title and message in alertdialog but am not able to achieve this by following way.
CustomAlertDialogBuilder.java :
public class CustomAlertDialogBuilder extends AlertDialog.Builder {
public CustomAlertDialogBuilder(Context context) {
super(context);
TextView title = (TextView) create().getWindow().findViewById(R.id.alertTitle);
TextView message = (TextView) create().getWindow().findViewById(android.R.id.message);
myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/my_font.ttf");
title.setTypeface(myTypeface);
message.setTypeface(myTypeface);
}
}
infact the TextView's are null. How do I define TextViews? I'm a beginner, Please help me to change font of alertdialog with create custom alertdialog.
I use custom dialogs quite often so I use DialogFragment. Note this dialog has an "Ok" and "Cancel" buttons. You can remove the buttons if you do not need them.
You need to create an XML Layout for the Custom DialogFragment "fragment_submit_cancel_dialog". The ability to create your own design gives you a great deal of flexibility in the appearance of your dialog.
In the Activity you call the DialogFragment you will need to add this:
implements OkCancelDialogFragment.OkCancelDialogListener{
and add the listener method:
#Override
public void onFinishOkCancelDialog(boolean submit) {
if(submit){
// Do what you need here
}
}
Call the DialogFragment like this:
private void startOkDialog(){
String title = "What ever you want as a Title";
String mess = "Your Message!";
OkCancelDialogFragment dialog = OkCancelDialogFragment.newInstance(title, mess);
show(getFragmentManager(), "OkDialogFragment");
}
Now the code for the Custom Dialog Fragment:
public class OkCancelDialogFragment extends DialogFragment {
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
Context context = null;
private String title;
private String message;
private boolean submitData = false;
private OkCancelDialogListener mListener;
public OkCancelDialogFragment() {
}
public static OkCancelDialogFragment newInstance(String title, String message) {
OkCancelDialogFragment fragment = new OkCancelDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
title = getArguments().getString(ARG_TITLE);
message = getArguments().getString(ARG_MESSAGE);
}
}
#Override
public Dialog onCreateDialog(Bundle saveIntsanceState){
context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fragment_submit_cancel_dialog, null, false);
final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);
titleView.setText(title);
messView.setText(message);
builder.setView(rootView)
.setPositiveButton(R.string.button_Ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
submitData = true;
//The onDetach will call the Listener! Just in case the user taps the back button
}
})
.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
submitData = false;
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
if(mListener == null) mListener = (OkCancelDialogListener) context;
}
catch (Exception ex){
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener.onFinishOkCancelDialog(submitData);
mListener = null;
}
public interface OkCancelDialogListener {
void onFinishOkCancelDialog(boolean submit);
}
}

Handling external class dialog button in main activity

I am trying to create a custom dialog where the button clicks could be handled by the main activity that instantiates it, something like how the AlertDialog.Builder assigns the listeners via its setPositiveButton() and setNegativeButton() methods.
This is what I've done:
// THE MAIN ACTIVITY
public class main_code extends AppCompatActivity {
private commonModule comMod;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
comMod = new commonModule(this);
}
private void showDialog() {
DialogInterface.OnClickListener dialogHandler =
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// process "PROCEED" button
}
};
commonModule.myDialog customDialog = comMod.new myDialog();
customDialog.inputBox(this, "Submit Results",
"Your results will be submitted.", dialogHandler);
}
}
// THE COMMON MODULE CLASS
public class commonModule {
public commonModule(Context context){
this.context = context;
this.activity = (Activity) context;
}
public class myDialog {
public void showDialog(Activity activity, String title, String message,
DialogInterface.OnClickListener dialogHandler) {
final Dialog panel = new Dialog(activity);
panel.requestWindowFeature(Window.FEATURE_NO_TITLE);
panel.setContentView(R.id.customLayout);
panel.setCancelable(false);
TextView panelTitle = (TextView) panel.findViewById(R.id.title);
panelTitle.setTypeface(fontRes(PlayRegular));
panelTitle.setText(title);
TextView msgboxText = (TextView) panel.findViewById(R.id.content);
msgboxText.setTypeface(fontRes(PlayRegular));
msgboxText.setText(message);
Button button1 = (Button) panel.findViewById(R.id.button1);
button1.setTypeface(fontRes(PlayRegular));
button1.setText("ABORT");
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
panel.dismiss();
}
});
Button button2 = (Button) panel.findViewById(R.id.button2);
button2.setTypeface(fontRes(PlayRegular));
button2.setText("PROCEED");
button2.setOnClickListener(dialogHandler);
// error: View.OnClickListener cannot be applied to Dialog.OnClickListener
panel.show();
}
}
}
I tried using View.OnClickListener() as well, but to no success. I would like the dialog builder to be common and generic, and as such, the click listener should be unique for each dialog.
Any suggestion would be really appreciated.
TIA.
Change your dialogHandler to View.OnClickListener instead of DialogInterface.OnClickListener :
private void showDialog() {
View.OnClickListener dialogHandler =
new View.OnClickListener() {
#Override
public void onClick(View v) {
// process "PROCEED" button
}
};
commonModule.myDialog customDialog = comMod.new myDialog();
customDialog.inputBox(this, "Submit Results",
"Your results will be submitted.", dialogHandler);
}
and in the common module:
public void showDialog(Activity activity, String title, String message,
View.OnClickListener dialogHandler) {
...
button2.setOnClickListener(dialogHandler);
panel.show();
}

Implement DialogFragment interface in OnClickListener

I need to build a DialogFragment which returns user input from the dialog to an activity.
The dialog needs to be called in an OnClickListener which gets called when an element in a listview gets clicked.
The return value of the DialogFragment (the input of the user) should be directly available in the OnClickListener in the activity.
I tried to implement this by sticking to the official docs: http://developer.android.com/guide/topics/ui/dialogs.html#PassingEvents
I need something like the following which doesn't work since I don't know how to make the anonymous OnClickListener implement the interface of the CustomNumberPicker class.
As far as I know implementing the interface is necessary in order to get data from the DialogFragment back to the Activity.
Main Activity:
public class MainAcitivity extends ActionBarActivity {
[...]
// ArrayAdapter of the Listview
private class ListViewArrayAdapter extends ArrayAdapter<Exercise> {
public ListViewArrayAdapter(Context context, ArrayList<Exercise> exercises) {
super(context, 0, exercises);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
[...]
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_workoutdetail, parent, false);
}
TextView tvSets = (TextView) convertView.findViewById(R.id.tvWorkoutExerciseSets);
tvSets.setText(sets.toString());
// OnClickListener for every element in the ListView
tvSets.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// This is where the Dialog should be called and
// the user input from the Dialog should be returned
DialogFragment numberpicker = new CustomNumberPicker();
numberpicker.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
}
// Here I would like to implement the interface of CustomNumberPicker
// in order to get the user input entered in the Dialog
});
return convertView;
}
}
}
CustomNumberPicker (basically the same as in the docs):
public class CustomNumberPicker extends DialogFragment {
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
// Use this instance of the interface to deliver action events
NoticeDialogListener mListener;
// Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
// Instantiate the NoticeDialogListener so we can send events to the host
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Return stuff here to the activity?
}
})
.setNegativeButton("cancle", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
Something like this?
public class CustomNumberPicker extends DialogFragment {
private NoticeDialogListener ndl;
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
//add a custom constructor so that you have an initialised NoticeDialogListener
public CustomNumberPicker(NoticeDialogListener ndl){
super();
this.ndl=ndl;
}
//make sure you maintain an empty constructor
public CustomNumberPicker( ){
super();
}
// Use this instance of the interface to deliver action events
NoticeDialogListener mListener;
// Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//remove the check that verfis if your activity has the DialogListener Attached because you want to attach it into your list view onClick()
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ndl.onDialogPositiveClick(dialog);
}
})
.setNegativeButton("cancle", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ndl.onDialogNegativeClick(dialog);
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
and then your listView onClick becomes:
tvSets.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// This is where the Dialog should be called and
// the user input from the Dialog should be returned
//
//
DialogFragment numberpicker = new CustomNumberPicker(new NoticeDialogListener() {
#Override
public void onDialogPositiveClick(DialogFragment dialog) {
//What you want to do incase of positive click
}
#Override
public void onDialogNegativeClick(DialogFragment dialog) {
//What you want to do incase of negative click
}
};);
numberpicker.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
}
// Here I would like to implement the interface of CustomNumberPicker
// in order to get the user input entered in the Dialog
});
Do read the comments I have added.And it can even be further optimized because you really dont need an entire dialog instance to get the values you need.
EDIT a possible optimization could be:
Changing the Listener interface to :
public interface NoticeDialogListener {
public void onDialogPositiveClick(String output);
public void onDialogNegativeClick(String output);
//or whatever form of output that you want
}
Then modify the implemented methods accordingly.
You should have your activity, implement your interface (NoticeDialogListener).
public class MainActivity extends ActionBarActivity implements
NoticeDialogListener{
#Override
public void onDialogPositiveClick(DialogFragment dialog){
//Do something
}
#Override
public void onDialogNegativeClick(DialogFragment dialog){
//Do some other things
}
[...]
}
Then in your button click listeners of the dialog, you use the mListener and call the methods, which is now implemented in the activity and the code will be executed there.
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if(mListener != null)
mListener.onDialogPositiveClick(CustomNumberPicker.this);
}
});
Also note that you should set the mListener to null in the onDetach() method of your DialogFragment.
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
Here's how it's done:
In the Activity where you show the DiaogFragment, set the arguments of the DialogFragment with the desired name value pair.
Also make sure that the activity implements the DialogInterface.OnClickListener
In the overridded onClick pick up the value from the aforementioned name value pair
public class MainActivity extends AppCompatActivity implements DialogInterface.OnClickListener {
private static SettingsFragment settingsFragment;
private Button btnSettings;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btnSettings = (Button) findViewById(R.id.btnSettings);
btnSettings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
settingsFragment = new SettingsFragment();
Bundle bundle = new Bundle();
bundle.putString("myKey", null);
settingsFragment.setArguments(bundle);
//Use the commented out line below if you want the click listener to return to a fragment instead of an activity
//assuming that this class in a fragment and not an activity
//rotateSettingsFragment.setTargetFragment(getActivity().getSupportFragmentManager().findFragmentByTag("TagForThisFragment"), 0);
settingsFragment.setTargetFragment(settingsFragment, 0);
settingsFragment.setCancelable(true);
settingsFragment.show(getSupportFragmentManager(), "SettingsFragment");
}
});
}
#Override
public void onClick(DialogInterface dialog, int which) {
if(getResources().getResourceEntryName(which).equals("btnSettingFragmentClose")) {
String myValue = settingsFragment.getArguments().getString("myKey");
dialog.dismiss();
}
}
}
In your DialogFragment declare a DialogInterface.OnClickListener and cast it to the activity in the onAttach.
In the event that needs to send back the data to the activity; set the buddle arguments and then call the onClickListener.onClick
public class SettingsFragment extends DialogFragment {
private View rootView;
private Button btnSettingFragmentClose;
private DialogInterface.OnClickListener onClickListener;
public SettingsFragment() {}
/* Uncomment this and comment out on onAttach when you want to return to a fragment instead of an activity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onClickListener = (DialogInterface.OnClickListener) getTargetFragment();
}
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_settings, container, false);
btnSettingFragmentClose = (Button) rootView.findViewById(R.id.btnSettingFragmentClose);
btnSettingFragmentClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getArguments().putString("myKey", "Hello World!");
onClickListener.onClick(getDialog(), v.getId());
}
});
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
onClickListener = (DialogInterface.OnClickListener) activity;
}
catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement mainFragmentCallback");
}
}
}
This simple solution works for me:
public class MyActivity implements MyDialogFragment.Listener {
// ...
#Override
public void onMyEvent() {
// do something here
}
}
public class MyDialogFragment extends DialogFragment {
private Listener mCallback;
public interface Listener {
void onMyEvent();
}
#SuppressLint("RestrictedApi")
#Override
public void setupDialog(final Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.dialog_fragment_custom, null);
dialog.setContentView(contentView);
mCallback = (Listener) getActivity();
Button myBtn = (Button) dialog.findViewById(R.id.btn_custom);
myBtn.setOnClickListener(v -> {
mCallback.onMyEvent();
dismiss();
});
}
}
As an example you can use DatePickerDialog where DatePickerDialog.OnDateSetListener used to deliver result.
or this is one of my implementations that allow to keep dialog screen open until user not finished with some action or not entered valid data. With custom callback that provide exact interface to this dialog.
public class ConfirmPasswordDialog extends DialogFragment {
private OnPaswordCheckResult resultListener;
private TextView passwordView;
public ConfirmPasswordDialog(OnPaswordCheckResult resultListener){
this.resultListener = resultListener;
}
#Override
public android.app.Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_layout, null);
builder.setView(dialogView);
passwordView = (TextView) dialogView.findViewById(R.id.password);
passwordView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {/*do nothing*/}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {/*do nothing*/}
#Override
public void afterTextChanged(Editable s) {
if(passwordView != null){
passwordView.setError(null);
}
}
});
builder.setView(dialogView);
builder.setMessage("Please enter password to finish with action");
builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
/* do something when click happen, in this case mostly like dummy because data return later
* after validation or immediately if required*/
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setTitle("Confirm password");
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(final DialogInterface dialogInterface) {
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
if(passwordView == null || !isAdded()){
return;
}
String password = passwordView.getText().toString();
if(PrefUtils.isPasswordValid(getActivity(), password)){
if(resultListener == null){
return;
}
/* Return result and dismiss dialog*/
resultListener.onValidPassword();
dialog.dismiss();
} else {
/* Show an error if entered password is invalid and keep dialog
* shown to the user*/
String error = getActivity().getString(R.string.message_password_not_valid);
passwordView.setError(error);
}
}
});
}
});
return dialog;
}
/**
* Custom callback to return result if entered password is valid
*/
public static interface OnPaswordCheckResult{
void onValidPassword();
}
}

Categories