Warm tip: This article is reproduced from serverfault.com, please click

Listener for custom dialog null

发布于 2020-11-27 16:26:51

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);
    }

}

Questioner
Nikola Đuranović
Viewed
0
Son Truong 2020-11-28 09:57:01

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();