自定义Dialog结合ROOM数据库时EditText空指针异常求助
问题描述
我正尝试实现从自定义Dialog的EditText中获取字符串并添加到ROOM数据库的功能,其余功能均正常,但点击Dialog的“ok”按钮时程序崩溃。我无法明确如何在insertDataToDatabase函数中正确初始化Dialog内的EditText。
报错信息
java.lang.NullPointerException: Attempt to invoke virtual method
android.text.Editable android.widget.EditText.getText() on a null
object reference at
com.example.planner3.MainActivity.insertDataToDatabase(MainActivity.kt:75)
at
com.example.planner3.MainActivity.showAddDialog$lambda-2(MainActivity.kt:100)
相关代码
MainActivity.kt
package com.example.planner3 import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.text.TextUtils import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import android.view.Menu import android.view.MenuItem import android.widget.EditText import android.widget.Toast import androidx.lifecycle.ViewModelProvider import com.example.planner3.databinding.ActivityMainBinding import com.example.planner3.model.User import com.example.planner3.viewmodel.UserViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding private lateinit var mUserViewModel: UserViewModel override fun onCreate(savedInstanceState: Bundle?) { WindowCompat.setDecorFitsSystemWindows(window, false) super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) mUserViewModel = ViewModelProvider(this)[UserViewModel::class.java] setSupportActionBar(binding.toolbar) val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) supportActionBar!!.setBackgroundDrawable(ColorDrawable(Color.parseColor("#59da66"))) binding.floatingActionButton.setOnClickListener { //navController.navigate(R.id.action_RecyclerFragment_to_AddFragment) showAddDialog() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_main, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return when (item.itemId) { R.id.action_settings -> true else -> super.onOptionsItemSelected(item) } } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment_content_main) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } private fun insertDataToDatabase() { val editText = findViewById<EditText>(R.id.editTextDialog) val task = editText.text.toString() if(inputCheck(task)) { // Create an entity val user = User(0, task) mUserViewModel.addUser(user) Toast.makeText(this, "Task added", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "Please fill out required fields", Toast.LENGTH_SHORT).show() } } private fun inputCheck(task: String): Boolean { return !(TextUtils.isEmpty(task)) } private fun showAddDialog() { MaterialAlertDialogBuilder(this) .setView(R.layout.fragment_add) .setNegativeButton("cancel") { _, _ -> // Respond to negative button press } .setPositiveButton("ok") { _, _ -> // Respond to positive button press insertDataToDatabase() } .show() } }
fragment_add.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="15dp" tools:ignore="UselessParent"> <EditText android:id="@+id/editTextDialog" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:gravity="center" android:hint="Hint" android:paddingTop="15dp" android:textColorHint="#757575" tools:ignore="Autofill,TextFields" /> </LinearLayout> </LinearLayout>
解决方案
崩溃的核心原因是:你调用findViewById<EditText>(R.id.editTextDialog)时,是从Activity的视图层级中查找控件,但这个EditText属于Dialog的独立布局,不在Activity的视图树里,所以返回null,后续调用getText()就触发了空指针异常。
修改步骤如下:
- 在
showAddDialog方法中,先手动inflate出Dialog的布局,获取到EditText的引用。 - 点击ok按钮时,直接用这个引用获取输入内容,再传递给插入数据库的方法。
修改后的代码片段:
// 修改insertDataToDatabase方法,接收传入的task参数 private fun insertDataToDatabase(task: String) { if(inputCheck(task)) { val user = User(0, task) mUserViewModel.addUser(user) Toast.makeText(this, "Task added", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "Please fill out required fields", Toast.LENGTH_SHORT).show() } } private fun showAddDialog() { // 先加载Dialog的布局,获取到EditText引用 val dialogView = layoutInflater.inflate(R.layout.fragment_add, null) val editText = dialogView.findViewById<EditText>(R.id.editTextDialog) MaterialAlertDialogBuilder(this) .setView(dialogView) // 设置加载好的布局 .setNegativeButton("cancel") { _, _ -> } .setPositiveButton("ok") { _, _ -> val task = editText.text.toString() insertDataToDatabase(task) // 把输入内容传进去 } .show() }
这样修改后,就能正确获取到Dialog内EditText的引用,避免空指针问题,同时逻辑也更清晰。
内容的提问来源于stack exchange,提问作者Juncu
相关产品推荐
相关产品推荐

