Search code examples
androidkotlinandroid-room

App crashes when data is written to ROOM database error in description


when the app is ran the following error occurs:

2022-08-03 15:41:29.243 21219-21250/com.example.roomdatabasetest E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
    Process: com.example.roomdatabasetest, PID: 21219
    kotlin.UninitializedPropertyAccessException: **lateinit property userDB has not been initialized**
        at com.example.roomdatabasetest.MainActivity$writeData$1.invokeSuspend(MainActivity.kt:52)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Basically I need to know how to initialise the User DB

If you require anymore code then please ask and any help is greatly appreciated.

Main Activity

package com.example.roomdatabasetest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import com.example.roomdatabasetest.data.User
import com.example.roomdatabasetest.data.UserDatabase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch


class MainActivity : AppCompatActivity() {


    private lateinit var btnWriteData: Button
    private lateinit var btnReadData: Button
    private lateinit var etFirstName: EditText
    private lateinit var etLastName: EditText
    private lateinit var userDB : UserDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnWriteData = findViewById(R.id.btnWriteData)
        btnReadData = findViewById(R.id.btnReadData)
        etFirstName = findViewById(R.id.etFirstName)
        etLastName = findViewById(R.id.etLastName)



        btnWriteData.setOnClickListener{
            writeData()
        }

        btnReadData.setOnClickListener{
            readData()
        }
    }

    private fun writeData() {
        val firstName = etFirstName.text.toString()
        val lastName = etLastName.text.toString()

        if(firstName.isNotEmpty() && lastName.isNotEmpty()) {
            val user = User(
                null, firstName, lastName
            )
            GlobalScope.launch(Dispatchers.IO){
                userDB.userDao().insertAll(user)
            }
            etFirstName.text.clear()
            etLastName.text.clear()

            Toast.makeText(this, "Data Written", Toast.LENGTH_SHORT).show()
        }else{
            Toast.makeText(this, "Could Not Write Data", Toast.LENGTH_SHORT).show()
        }
    }

    private fun readData(){



    }
}

Solution

  • As the message says, you are not initialising the UserDb.

    Either you need to use something along the lines of:-

    User db = Room.databaseBuilder(this,UserDatabase::class.java,"the_database_name).allowMainThreadQueries().build()
    
    • in both case initialising userDb would probably be done as part of the onCreate function (probably straight after retrieving the View id's)

    Or if you use a singleton approach, which returns an instance of UserDatabase, which would require the context to be passsed to it and assuming the function, within the/a companion object is getInstance then

    UserDb = UserData.getInstance(this)
    

    Here's an example of a singleton approach but this would have to be modified to suit.

    @Database(....) /* .... WILL HAVE TO BE CHANGED */
    abstract class UserDatabase: RoomDatabase() {
        abstract fun userDao: UserDao
    
        companion object {
            @Volatile
            private var instance: UserDatabase?=null
            fun getInstance(context: Context): UserDatabase {
                if (instance==null) {
                    instance = Room.databaseBuilder(context,UserDatabase::class.java,"the_name_of_the_user_database")
                        .allowMainThreadQueries() /* as you are accessing the database on the main thread this will be required */    
                        .build()
                }
                return instance as UserDatabase
            }
        }
    }
    
    • note that it is not recommended to access the database on the main thread, but you can.