I'm getting a NullPointerException for my listener in my class, even though everything should be working fine. I followed Coding in Flow's tutorial for the custom dialog, rewatched it a few times and checked source code and I didn't miss anything. here's the code
Fragment the dialog is called from
public class FragmentMain extends Fragment implements CustomDialog.DialogListener {
.
.
.
private int timeLimit = 0;
private Button dialogOpen;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
.
.
.
dialogOpen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DialogDashboard dialogDashboard = new DialogDashboard();
dialogDashboard.show(getActivity().getSupportFragmentManager(), "notif_dialog");
}
}); //dialog called here
return view;
}
//getting text from spinner in dialog
#Override
public void applyText(String time) {
switch (time) {
case "30 Minutes":
timeLimit = 30;
case "1 Hour":
timeLimit = 60;
case "2 Hours":
timeLimit = 120;
case "4 Hours":
timeLimit = 240;
case "5 Hours":
timeLimit = 300;
}
}
}
Dialog Code:
public class CustomDialog extends AppCompatDialogFragment {
private Button confirmButton;
private Spinner spinner;
private DialogListener listener;
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
R.style.NotificationAlertDialog);
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.custom_dialog_notif, null);
confirmButton = view.findViewById(R.id.dialogButton);
spinner = view.findViewById(R.id.dialogSpinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.spinner_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
confirmButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String time = spinner.getSelectedItem().toString();
listener.applyText(time); // says listener is null when I just do e.printStackTrace();
dismiss();
}
});
builder.setView(view)
.setCancelable(true);
return builder.create();
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
listener = (DialogListener) context;
} catch (Exception e) {
e.printStackTrace();
throw new ClassCastException(context.toString() +
"must implement dialog listener"); // this says if the listener is null, but even if it's implemented it returns null...
}
}
public interface DialogListener {
void applyText(String time);
}
}
Root cause
You got NPE because onAttach() callback is called when the fragment is attached to its host/activity. The context param is the activity itseft, not the FragmentMain.
Solution
Step 1: When you click on the open dialog button in FragmentMain.
CustomDialog dialogDashboard = new CustomDialog();
dialogDashboard.show(getChildFragmentManager(), "notif_dialog");
Step 2: Modify the code in CustomDialog
Remove this code
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
listener = (DialogListener) context;
} catch (Exception e) {
e.printStackTrace();
throw new ClassCastException(context.toString() +
"must implement dialog listener");
}
}
When users click on the confirm button.
String time = spinner.getSelectedItem().toString();
Fragment fragment = getParentFragment();
if (fragment instanceof CustomDialog.DialogListener) {
listener = (DialogListener) fragment;
listener.applyText(time);
}
dismiss();
Related
I know there are similar questions but I couldn't find an answer to solve my problem.
I have a DialogUpdateEmail which I want to be opened from ProfileFragment. In the dialog I want to enter my new email and send it to my ProfileFragment in order to change it also in the database.
ProfileFragment.java :
import androidx.fragment.app.Fragment;
public class ProfileFragment extends Fragment implements SendInputEmail {
public static final int PROFILE_FRAGMENT = 1;
private static final String TAG = "ProfileFragment";
private TextView TVHello, TVUsernameMessage, TVusernameinfo, TVemailinfo, TVbirthdate;
public void sendInput(String input) {
Log.d(TAG, "sendInput: found incoming input: " + input);
TVemailinfo.setText(input);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_profile, container, false);
Button Bsignout = (Button) v.findViewById(R.id.signoutbutton);
Button Beditusername = (Button) v.findViewById(R.id.editusernamebutton);
Button Beditemail = (Button) v.findViewById(R.id.editemailbutton);
Beditemail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: opening email dialog");
DialogUpdateEmail dialog = new DialogUpdateEmail();
dialog.setTargetFragment(ProfileFragment.this,PROFILE_FRAGMENT);
dialog.show(getActivity().getFragmentManager(), "DialogUpdateEmail");
}
});
return v;
}
DialogUpdateEmail.java :
public class DialogUpdateEmail extends DialogFragment implements SendInputEmail {
private static final String TAG = "DialogUpdateEmail";
SendInputEmail mHost = (SendInputEmail)getTargetFragment();
public View onCreateView(final LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.popup, container, false);
EditText UpdateEmail = (EditText) view.findViewById(R.id.emailinfoupdate);
Button Beditemail = (Button) view.findViewById(R.id.updatesavebutton);
Button Bcancelemail = (Button) view.findViewById(R.id.updatecancelbutton);
Beditemail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: capturing input.");
String input = UpdateEmail.getText().toString();
Log.d(TAG, "input : "+input);
mHost.sendInput(input);
getDialog().dismiss();
}
});
return view ;
}
public void onAttach(Context context) {
super.onAttach(context);
try{
mHost = (SendInputEmail) getTargetFragment();
}catch (ClassCastException e){
Log.e(TAG, "onAttach: ClassCastException : " + e.getMessage() );
}
}
#Override
public void sendInput(String input) {
}
}
SendInputEmail Interface :
public interface SendInputEmail {
void sendInput(String input);
}
My problem is that I have an error when I try to use setTargetFragment in ProfileFragment. It says that Profile Fragment is not a Fragment, I really don't know why.
From doc in here :
public class DialogUpdateEmail extends DialogFragment {
private DialogEditListener listener;
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = requireActivity().getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View view = inflater.inflate(R.layout.popup, null);
builder.setView(view);
EditText UpdateEmail = (EditText) view.findViewById(R.id.emailinfoupdate);
Button Beditemail = (Button) view.findViewById(R.id.updatesavebutton);
Button Bcancelemail = (Button) view.findViewById(R.id.updatecancelbutton);
Beditemail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
listener.onDialogEditClick(UpdateEmail.getText().toString());
DialogUpdateEmail.this.getDialog().dismiss();
}
}
});
Bcancelemail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DialogUpdateEmail.this.getDialog().cancel();
}
});
return builder.create();
}
public interface DialogEditListener {
void onDialogEditClick(String email);
}
public void setListener(DialogEditListener listener) {
this.listener = listener;
}
}
We send the email from the dialog to the fragment using the observer/listener pattern.
And in your ProfileFragment just implement DialogEditListener and subscribe it to listen for click button in the dialog like so:
public class ProfileFragment extends Fragment
implements SendInputEmail, DialogUpdateEmail.DialogEditListener {
public static final int PROFILE_FRAGMENT = 1;
private static final String TAG = "ProfileFragment";
private TextView TVHello, TVUsernameMessage, TVusernameinfo, TVemailinfo, TVbirthdate;
public void sendInput(String input) {
Log.d(TAG, "sendInput: found incoming input: " + input);
TVemailinfo.setText(input);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_profile, container, false);
Button Bsignout = (Button) v.findViewById(R.id.signoutbutton);
Button Beditusername = (Button) v.findViewById(R.id.editusernamebutton);
Button Beditemail = (Button) v.findViewById(R.id.editemailbutton);
Beditemail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: opening email dialog");
//show your dialog
DialogUpdateEmail dialogUpdateEmail = new DialogUpdateEmail();
dialogUpdateEmail.setListener(ProfileFragment.this);
dialogUpdateEmail.show(getActivity().getSupportFragmentManager(), "DialogUpdateEmail");
}
});
return v;
}
#Override
public void onDialogEditClick(String email) {
//use your email here
Toast.makeText(getContext(), "My email: " + email, Toast.LENGTH_SHORT).show();
}
}
I am trying to pass information from my alert dialog to my second fragment (I am using tabbed activity layout).
I want to pass information from alert dialog to fragment when I click on my ImageView, but my app keep crashing until I implement my interface inside MainActivity.java. My main mission here is to open alert dialog which contains several buttons. When I click first button I want to print "Test br 3" but it does not work inside my Fragment, it only works inside my MainActivity.java where method prints "Test br 2".
My Main Activity
public class MainActivity extends AppCompatActivity implements ExercisesAlertDialog.DataTransfer {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
#Override
public void ApplyData() {
System.out.println("Test br 2");
}
My Fragment
public class Frag2 extends Fragment implements ExercisesAlertDialog.DataTransfer {
ImageView plusbtn;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag2, container, false);
plusbtn = (ImageView) v.findViewById(R.id.plusbtn);
plusbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ExercisesDialog();
}
});
return v;
}
public void ExercisesDialog()
{
ExercisesAlertDialog exercisesAlertDialog = new ExercisesAlertDialog();
exercisesAlertDialog.show(getFragmentManager(), "Exercises Dialog");
}
#Override
public void ApplyData() {
System.out.println("Test br 3");
}
My Alert Dialog
public class ExercisesAlertDialog extends AppCompatDialogFragment {
ImageButton one, two;
private DataTransfer listener;
public int first;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.workout_custom_menu, null);
builder.setView(v);
builder.setTitle("Choose your Workout");
builder.setPositiveButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
one = (ImageButton) v.findViewById(R.id.first);
two = (ImageButton) v.findViewById(R.id.second);
one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
first = 1;
if(first ==1)
{
listener.ApplyData();
}
}
});
return builder.create();
}
public interface DataTransfer
{
void ApplyData();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (DataTransfer) context;
}
catch (ClassCastException e)
{
throw new ClassCastException(toString() + "Must implement DataTransfer");
}
}
}
I changed getChildFragmentManager() instead of getFragmentManager() in the show() call. Second thing is onAttach() to listener = (DataTransfer) getParentFragment(); instead of context.
I am trying to make Dialog that will consist 2x EditText and 1x Buttons. By clicking additional button you can add another 2x EditText and 1x Buttons. This 1x Button provide deleting this added pair. When i try to use button that should add another Views it's working properly. But button for deleting the View is working only for the first pairs. How can i do this with android:onClick, because i was trying buy it crashed.
Here is my code of Dialog class:
public class ExampleDialog extends AppCompatDialogFragment {
private EditText editTextUsername;
private EditText editTextPassword;
private ExampleDialogListener listener;
private LinearLayout parentLinearLayout;
private Context mContext;
Button dodaj,usun;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_template, null);
builder.setView(view)
.setTitle("Login")
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
String username = editTextUsername.getText().toString();
String password = editTextPassword.getText().toString();
listener.applyTexts(username, password);
}
});
editTextUsername = view.findViewById(R.id.edit_username);
editTextPassword = view.findViewById(R.id.edit_password);
parentLinearLayout = (LinearLayout) view.findViewById(R.id.parent_linear_layout);
dodaj = view.findViewById(R.id.add_field_button);
usun = view.findViewById(R.id.delete_button);
dodaj.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView = inflater.inflate(R.layout.field, null);
// Add the new row before the add field button.
parentLinearLayout.addView(rowView, parentLinearLayout.getChildCount() - 1);
}
});
usun.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
parentLinearLayout.removeView((View) v.getParent());
usun = v.findViewById(R.id.delete_button);
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (ExampleDialogListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() +
"must implement ExampleDialogListener");
}
}
public void contexta(Context context)
{
this.mContext = context;
}
public interface ExampleDialogListener {
void applyTexts(String username, String password);
}
}
And there is the conception of Dialog box on the picture below:
Picture
This issue may be due to view reference. Check whether v.getParent() is the view you want to delete or not.
For testing you can use "removeViewAt(int index)" method. Pass an index and check whether view is deleted at index or not.
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);
}
}
I have an ItemClickListener in a gridview. But my itemclicklistener is not being called. There is no activity on item click of the gridview
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vi = inflater.inflate(R.layout.home, container, false);
Button startdialog = (Button) vi.findViewById(R.id.btnCreateDialog);
startdialog.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent startdialog = new Intent(getActivity(),
start_dialog.class);
startActivity(startdialog);
}
});
Button iv = (Button) vi.findViewById(R.id.btnMoreDialog);
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
PopupMenu homepopup = new PopupMenu(getActivity(), v);
MenuInflater inflater = homepopup.getMenuInflater();
inflater.inflate(R.menu.moredialog, homepopup.getMenu());
homepopup.show();
}
});
PremiumgridView = (StaggeredGridView) vi
.findViewById(R.id.premiumstaggeredGridView);
new Dialogs().execute(urls);
return vi;
}
private class Dialogs extends AsyncTask<String[], Void, String[]> {
#Override
protected String[] doInBackground(String[]... params) {
return params[0];
}
protected void onPostExecute(String[] result) {
int premiummargin = getResources().getDimensionPixelSize(
R.dimen.margin);
PremiumgridView.setItemMargin(premiummargin);
PremiumgridView.setPadding(premiummargin, 0, premiummargin, 0);
final StaggeredAdapter premiumadapter = new StaggeredAdapter(
vi.getContext(), R.id.photoimageview, result,
R.layout.row_staggered_demo);
PremiumgridView.setAdapter(premiumadapter);
premiumadapter.notifyDataSetChanged();
premiumadapter.onClick(vi);
PremiumgridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(StaggeredGridView parent, View view,
int position, long id) {
String item = premiumadapter.getItem(position).toString();
Toast.makeText(getActivity(), premiumadapter.getItem(position), Toast.LENGTH_SHORT).show();
// Toast.makeText(getActivity(), "You have chose: "+ item, Toast.LENGTH_LONG).show();
}});
}
#Override
protected void onPreExecute() {
}
}
Anyone please?
Thanks,
Solved the problem by removing the button from the xml. Clickable item cannot have another clickable item inside it. Reference OnItemClickListener Not Triggered on Android GridView
Does it crash? If yes, always provide us with the Stacktrace/Logcat.
As far as I know, it´s impossible to directly change the interface from within any Thread other than the UI-Thread - you could either try Handler or use this.
EDIT: OnPostExecute is actually called on the UI-Thread, so this is not a solution for this problem. (see here)