0

I have a class that extends the AppCompatDialogFragment. I want it to create a popup where the user can input their password. But I get this error every time I run the app.

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference

Here is my code for the class onCreateDialog method:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    //The popup
    val mBuilder = AlertDialog.Builder(activity)
    val mFlater = activity?.layoutInflater
    val mView =mFlater?.inflate(R.layout.activity_get_password, null)

    //Get the EditText
    val getPassword: EditText = mView!!.findViewById(R.id.getPassword)

    mBuilder.setPositiveButton("Ok"){ _, _ ->}

    //Set the view
    mBuilder.setView(mView)

    //Set the AlertDialog
    val alertDialog = mBuilder.create().apply {
        setCanceledOnTouchOutside(false)
    }

    //Set the clicklistener for the
    alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
        val password = getPassword.text.toString()
        if(password == db?.getPassword()) {
            //Send the password
            interfaces?.getPassword(password)

            //Close the alert dialog
            alertDialog.dismiss()
        } else //Wrong password?
            Toast.makeText(context, "Invalid Password!", Toast.LENGTH_LONG).show()
    }

    return alertDialog
}
Ryan M
  • 18,333
  • 31
  • 67
  • 74

2 Answers2

0

You must call show() before getButton(). If you want automatically set ClickListener callback when dialog is shown, check this answer.


You need to know about platform type. When calling java method in kotlin, it will return platform type unless you use @NotNull or @Nullable annotations.

For example, alertDialog.getButton() returns platform type(null). Kotlin behaves like non-null, whether the return value is null or non-null, because it is platform type. So even if null is returned, null.setOnClickListener() is called.

galcyurio
  • 1,776
  • 15
  • 25
0

Root cause: From AlertDialog source code:

/**
 * Gets one of the buttons used in the dialog. Returns null if the specified
 * button does not exist or the dialog has not yet been fully created (for
 * example, via {@link #show()} or {@link #create()}).
 *
 * @param whichButton The identifier of the button that should be returned.
 *                    For example, this can be
 *                    {@link DialogInterface#BUTTON_POSITIVE}.
 * @return The button from the dialog, or null if a button does not exist.
 */
public Button getButton(int whichButton) {
    return mAlert.getButton(whichButton);
}

In your case, the getButton() method return null because the dialog has not been fully created via show() or create().

Solution: Calling one of these two methods before calling the getButton() method to make sure the dialog has been fully created.

// Set the AlertDialog
val alertDialog = mBuilder.create().apply {
    setCanceledOnTouchOutside(false)
}

// Calling show or create method here
alertDialog.show(); // or alertDialog.create();

// Set the clicklistener for the
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
    val password = getPassword.text.toString()
    if (password == db?.getPassword()) {
        //Send the password
        interfaces?.getPassword(password)

        //Close the alert dialog
        alertDialog.dismiss()
    } else { //Wrong password?
        Toast.makeText(context, "Invalid Password!", Toast.LENGTH_LONG).show()
    }
}
Son Truong
  • 13,661
  • 5
  • 32
  • 58