'Android Kotlin findViewById must not be null
We have created a custom alert dialog that was used in a Java project by converting it to Kotlin The error posted below java.lang.IllegalStateException: findViewById(R.id.btnYES) must not be null
The error source is eluding us ! We have looked at a number of posts and tried a few with no results. The Activity structure is as follows PageTwoActivity has its own XML file with two buttons attached. The custom dialog has its own xml file Here is the PageTwoActivity code. Without the two buttons for PageTwoActivity NO name conflicts
import android.app.Dialog
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
class PageTwoActivity : AppCompatActivity() {
internal lateinit var btnBACK: Button
internal lateinit var btnDIALOG: Button
internal lateinit var btnYES: Button
internal lateinit var btnNO: Button
internal lateinit var etStudentName:EditText
var EnteredText: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_page_two)
btnBACK = findViewById(R.id.btnBACK)
btnDIALOG = findViewById(R.id.btnDIALOG)
btnYES = findViewById(R.id.btnYES)
btnNO = findViewById(R.id.btnNO)
etStudentName = findViewById(R.id.etStudentName)
addListenerOnButtonBACK()
addListenerOnButtonDIALOG()
Toast.makeText(this@PageTwoActivity, "You are on Page Two",
Toast.LENGTH_LONG).show()
}// END onCreate
Here is the code for the Custom Dialog
private fun doCustom() {
val openDialog = Dialog(this)
openDialog.setContentView(R.layout.custom_dialog)
//val btnYES = view!!.findViewById<Button>(R.id.btnYES)
//val btnNO = openDialog.findViewById(R.id.btnNO)
//val etStudentName = openDialog.findViewById(R.id.etStudentName)
openDialog.setCancelable(false)
btnYES.setOnClickListener(View.OnClickListener {
EnteredText = etStudentName.getText().toString().trim({ it <= ' ' })
if (EnteredText.isEmpty()) {
Toast.makeText(applicationContext, "Enter Your Name\n\n OR Click
DECLINE", Toast.LENGTH_LONG).show()
return@OnClickListener
}
Toast.makeText(applicationContext, "Registered $EnteredText",
Toast.LENGTH_SHORT).show()
openDialog.dismiss()
})
btnNO.setOnClickListener(View.OnClickListener {
EnteredText = ""
val intent = Intent(this@PageTwoActivity, MainActivity::class.java)
startActivity(intent)
openDialog.dismiss()
})
openDialog.show()
}
The XML file code for the custom dialog
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="400dp"
android:layout_height="200dp"
android:background="@color/color_lightGray">
<TextView
android:id="@+id/tvDAT"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:layout_marginTop="30dp"
android:text="Enter First and Last Name"
android:textColor="@color/color_Black"
android:textSize="22sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etStudentName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="80dp"
android:ems="14"
android:gravity="center"
android:inputType="textPersonName"
android:text=""
android:textColor="@color/color_Black"
android:textSize="20sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnYES"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="250dp"
android:layout_marginTop="120dp"
android:background="@color/color_Transparent"
android:text="TAKE QUIZ"
android:textColor="@color/color_deepBlue"
android:textSize="22sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnNO"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="22dp"
android:layout_marginTop="120dp"
android:background="@color/color_Transparent"
android:text="DECLINE"
android:textColor="@color/color_deepBlue"
android:textSize="22sp"
android:textStyle="bold" />
</RelativeLayout>
So the question is how do we FIX the error? Should we be inflating the custom dialog xml? As you can see we tried to move the declaration to find the id into the doCustom function //val btnYES = view!!.findViewById(R.id.btnYES) this link offers advice but we have no idea where to start LINK
Solution 1:[1]
As @Declan Nnadozie already mentioned: btnYES = findViewById(R.id.btnYES)
returns null
because btnYES
is not a view inside the contentView
inflated to PageTwoActivity
.
The buttons btnYES
and btnNO
and the EditText etStudentName
can be found in the content that is inflated in the dialog:
Also in Kotlin you do not need findViewById to access the activity's views.
You can delete all these:
internal lateinit var btnBACK: Button
internal lateinit var btnDIALOG: Button
internal lateinit var btnYES: Button
internal lateinit var btnNO: Button
internal lateinit var etStudentName:EditText
My suggestion is to use the below code:
class PageTwoActivity : AppCompatActivity() {
var EnteredText: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_page_two)
addListenerOnButtonBACK()
addListenerOnButtonDIALOG()
Toast.makeText(this@PageTwoActivity, "You are on Page Two",
Toast.LENGTH_LONG).show()
}
fun doCustom(v: View) {
val openDialog = Dialog(this)
openDialog.setContentView(R.layout.custom_dialog)
val btnYES = openDialog.findViewById<Button>(R.id.btnYES)
val btnNO = openDialog.findViewById<Button>(R.id.btnNO)
val etStudentName = openDialog.findViewById<EditText>(R.id.etStudentName)
openDialog.setCancelable(false)
btnYES.setOnClickListener(View.OnClickListener {
EnteredText = etStudentName.getText().toString().trim({ it <= ' ' })
if (EnteredText.isEmpty()) {
Toast.makeText(applicationContext, "Enter Your Name\n\n OR Click DECLINE", Toast.LENGTH_LONG).show()
return@OnClickListener
}
Toast.makeText(applicationContext, "Registered $EnteredText", Toast.LENGTH_SHORT).show()
openDialog.dismiss()
})
btnNO.setOnClickListener(View.OnClickListener {
EnteredText = ""
val intent = Intent(this@PageTwoActivity, MainActivity::class.java)
startActivity(intent)
openDialog.dismiss()
})
openDialog.show()
}
Solution 2:[2]
findViewByID()
returns a nullable object.
btnYES = findViewById(R.id.btnYES)
Tries to assign a nullable view to a lateinit non-nullable view.
So here's the solution.
change this internal lateinit var btnYES: Button
to this internal lateinit var btnYES: Button?
Or
change this btnYES = findViewById(R.id.btnYES)
to this btnYES = findViewById(R.id.btnYES)!!
Solution 3:[3]
One approach that you can take is instead of trying to customize the Dialog by using setContentView, you can extend DialogFragment with a new Custom Dialog Fragment. Then you can approach it similar to how you would a fragment; You inflate a view in onCreateDialog, this is an approach I found in a similar question:
public class PopupAlert extends DialogFragment {
TextView heading;
TextView popupMessage;
Button okBtn;
private Runnable onDismissRunnable;
private String titleText;
private String messageText;
private View.OnClickListener positiveListener;
public void setOnDismissRunnable(Runnable runnable) {
this.onDismissRunnable = runnable;
}
public void setOkBtnText(String text) {
this.okBtnText = text;
}
public static PopupAlert newInstance(String title, String message) {
PopupAlert alert = new PopupAlert();
alert.titleText = title;
alert.messageText = message;
return alert;
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (onDismissRunnable != null) onDismissRunnable.run();
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@SuppressLint("InflateParams") View view = LayoutInflater.from(getContext()).inflate(R.layout.view_popup_alert, null);
fetchViews(view);
builder.setView(view);
return builder.create();
}
private void fetchViews(View view) {
heading = view.findViewById(R.id.popupHeading);
popupMessage = view.findViewById(R.id.popupMessage);
okBtn = view.findViewById(R.id.okBtn);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
bindToData();
}
private void bindToData() {
heading.setText(titleText);
popupMessage.setText(messageText);
okBtn.setOnClickListener((v) -> dismiss());
okBtn.setText(okBtnText);
}
}
Solution 4:[4]
I had the same problem. I solved it putting findViewById inside the customAlertButton.setOnClickListener:
customAlertButton.setOnClickListener {
val customDialog = Dialog(this)
customDialog.setContentView(R.layout.custom_alert_layout)
customDialog.show()
val button1 = customDialog.findViewById<View>(R.id.button1)
val button2 = customDialog.findViewById<View>(R.id.button2)
val button3 = customDialog.findViewById<View>(R.id.button3)
button1.setOnClickListener {
Toast.makeText(this, "Called by button1", Toast.LENGTH_SHORT).show()
}
button2.setOnClickListener {
Toast.makeText(this, "Called by button2", Toast.LENGTH_SHORT).show()
}
button3.setOnClickListener {
Toast.makeText(this, "Called by button3", Toast.LENGTH_SHORT).show()
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Declan Nnadozie |
Solution 3 | Corey Johnson |
Solution 4 | Roberto Luongo |