安卓 Kotlin findViewById 不能为空。

22

我们通过将其转换为Kotlin,创建了一个自定义警报对话框,并在Java项目中使用它。下面是发布的错误信息 java.lang.IllegalStateException: findViewById(R.id.btnYES) must not be null

我们无法找到错误源!我们查看了许多帖子并尝试了一些方法,但没有结果。Activity结构如下:PageTwoActivity有自己的XML文件和两个附加按钮。自定义对话框具有自己的xml文件 以下是PageTwoActivity代码。没有两个按钮用于PageTwoActivity 没有名称冲突

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

这是自定义对话框的代码

    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()
}
自定义对话框的 XML 文件代码。
<?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>

所以问题是如何解决这个错误?我们应该膨胀自定义对话框xml吗?正如您所看到的,我们尝试将声明移动到doCustom函数中查找id //val btnYES = view!!.findViewById(R.id.btnYES) 这个链接提供了建议,但我们不知道从哪里开始 LINK


添加堆栈跟踪 - Zoe stands with Ukraine
2
问题因为缺乏研究而被投票否决是不正确的,我们在各个地方甚至在Stackoverflow上查看了许多帖子,测试了大量代码,但都没有结果。我想补充说明的是,我们不会在没有阅读和研究至少4小时或2天的情况下提出问题。 - Vector
5个回答

17
如@Declan Nnadozie所提到的:btnYES = findViewById(R.id.btnYES) 返回null,因为btnYES不是在充入到PageTwoActivitycontentView中的视图。
按钮btnYESbtnNO和EditTextetStudentName可以在对话框中填充的内容中找到。
同样,在Kotlin中,您不需要findViewById来访问活动的视图。
您可以删除所有这些:
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

我的建议是使用以下代码:

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

0

findViewByID() 返回一个可为空的对象。

btnYES = findViewById(R.id.btnYES)

尝试将可为空的视图分配给延迟初始化的非空视图。
因此,以下是解决方案。 将此internal lateinit var btnYES: Button更改为此internal lateinit var btnYES: Button? 或者
将此btnYES = findViewById(R.id.btnYES)更改为此btnYES = findViewById(R.id.btnYES)!!

4
感谢您的反馈,但我需要告诉您这两个建议都会产生警告,因为它们是不允许的。因此,语法结构无法使用。 - Vector

0
一个方法是,你可以不要尝试使用setContentView来定制Dialog,而是通过使用一个新的自定义Dialog Fragment来扩展DialogFragment。然后你可以像处理Fragment一样来处理它;你可以在onCreateDialog中填充一个view,这是我在类似问题中找到的一种方法:
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);
    }
}

0
我遇到了同样的问题。我通过将findViewById放在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()
        }

    }

0
不是针对问题的提问者,而是一个常见的错误:
首先要检查的是,在调用findViewById之前,在onCreate()方法中是否已经添加了一行代码setContentView(R.layout.activity_your_activity_layout_name)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接