Android Kotlin findViewById 不能为空

Android Kotlin findViewById must not be null

我们通过将其转换为 Kotlin 创建了一个在 Java 项目中使用的自定义警报对话框下面发布的错误 java.lang.IllegalStateException: findViewById(R.id.btnYES) 不能为空

错误来源在躲避我们!我们查看了许多帖子并尝试了一些但没有结果。 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 吗? 如您所见,我们试图将用于查找 id 的声明移动到 doCustom 函数中 //val btnYES = view!!.findViewById(R.id.btnYES) 这个 link 提供了建议,但我们不知道从哪里开始 LINK

findViewByID() returns 一个可为 null 的对象。

btnYES = findViewById(R.id.btnYES)

尝试将可为 null 的视图分配给 lateinit 不可为 null 的视图。

这就是解决方案。 将此 internal lateinit var btnYES: Button 更改为此 internal lateinit var btnYES: Button?

将此 btnYES = findViewById(R.id.btnYES) 更改为此 btnYES = findViewById(R.id.btnYES)!!

您可以采用一种方法,而不是尝试使用 setContentView 自定义对话框,您可以使用新的自定义对话框片段扩展 DialogFragment。然后你可以像处理片段一样处理它;您在 onCreateDialog 中膨胀视图,这是我在类似问题中找到的一种方法:

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

正如@Declan Nnadozie 已经提到的那样:btnYES = findViewById(R.id.btnYES) returns null 因为 btnYES 不是 contentView 内的视图膨胀到 PageTwoActivity.
按钮 btnYESbtnNO 以及 EditText etStudentName 可以在对话框中膨胀的内容中找到:
同样在 Kotlin 中,您不需要 findViewById 来访问 activity 的视图。
您可以删除所有这些:

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

我遇到了同样的问题。我解决了将 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()
        }

    }