I'm trying to implement adding an item to database, which is a string from editText dialog. Everything is all right, except when I press the "ok" button in the dialog everything crashes. I can't really figure out how to initiate the editText in this dialog with the insertDataToDatabase function
It gives me this error:
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>
CodePudding user response:
at insertDataToDatabase add a arg of type DialogInterface then cast it to AlertDialog
private fun insertDataToDatabase(dialog: DialogInterface) {
val editText = (dialog as AlertDialog).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()
}
}
and at showAddDialog to make it clear change _ on setPositiveButton to dialogInterface , and passe it to insertDataToDatabase
private fun showAddDialog() {
MaterialAlertDialogBuilder(this)
.setView(R.layout.fragment_add)
.setNegativeButton("cancel") { _, _ ->
// Respond to negative button press
}
.setPositiveButton("ok") {dialogInterface, _ ->
// Respond to positive button press
insertDataToDatabase(dialogInterface)
}
.show()
}