Search code examples
androidkotlinnullpointerexceptionsqliteopenhelper

NullPointerException on Application startup using SQLite database


i'm relatively new to Kotlin and SQLite, and the application I have made using android studio keeps producing a NullPointerReference error.

My app takes input from the user and stores it into the SQLite database. It will then load entries onto the main page. When running my app for the 1st time, it produces the following error.

Logcat

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.reminders/com.example.reminders.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getDatabasePath(java.lang.String)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3654)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3806)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8167)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getDatabasePath(java.lang.String)' on a null object reference
        at android.content.ContextWrapper.getDatabasePath(ContextWrapper.java:337)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:445)
        at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:415)
        at com.example.reminders.FeedReaderDbHelper.viewReminder(DatabaseHandler.kt:61)
        at com.example.reminders.HistoryActivity.getItemsList(HistoryActivity.kt:37)
        at com.example.reminders.HistoryActivity.setupListofDataintoRecyclerView(HistoryActivity.kt:20)
        at com.example.reminders.MainActivity.onCreate(MainActivity.kt:99)
        at android.app.Activity.performCreate(Activity.java:7963)
        at android.app.Activity.performCreate(Activity.java:7952)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3629)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3806) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:237) 
        at android.app.ActivityThread.main(ActivityThread.java:8167) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100) 

Relevant code from my MainActivity

class MainActivity : AppCompatActivity() {

    lateinit var alarmService: AlarmService
    lateinit var historyActivity: HistoryActivity

    @RequiresApi(Build.VERSION_CODES.N)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
            setContentView(R.layout.history_main)
            createNotificationChannel()
            alarmService = AlarmService(this)
            historyActivity = HistoryActivity()
                                    
                            ...

    }
    historyActivity.setupListofDataintoRecyclerView(this)
}

On startup, i intend for it to check if number of items in the database is > 0. If greater, the app will load the database. if not, it will display that there are no entries.

Relevant Code from my HistoryActivity

    fun setupListofDataintoRecyclerView(context: Context) {
        if (getItemsList().size > 0) {
            tvEmptyHistory.visibility = View.GONE
            rvHistory.visibility = View.VISIBLE
            rvHistory.layoutManager = LinearLayoutManager(context)
            var itemAdapter = HistoryAdapter(context, getItemsList())
            rvHistory.adapter = itemAdapter
        }
        else {
            tvEmptyHistory.visibility = View.VISIBLE
            rvHistory.visibility = View.GONE
        }
    }

    private fun getItemsList(): ArrayList<reminderHistory> {
        //create instance of DatabaseHandler
        val databaseHandler = FeedReaderDbHelper(this)
        //call method to view database
        return databaseHandler.viewReminder()
    }

Relevant code from my FeedReaderDbHelper class

class FeedReaderDbHelper(context: Context) :
    SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

                            ...

    fun viewReminder(): ArrayList<reminderHistory> {
        val rHistList: ArrayList<reminderHistory> = ArrayList()
        val selectQuery = "SELECT * FROM $TABLE_CONTACTS"
        val db = this.readableDatabase
        var cursor: Cursor? = null

        try {
            cursor = db.rawQuery(selectQuery, null)
        } catch (e: SQLiteException) {
            db.execSQL(selectQuery)
            return ArrayList()
        }
        var id: Int
        var item: String
        var hour: Int
        var min: Int
        var date: String

        if (cursor.moveToFirst()) {
            do {
                id = cursor.getInt((cursor.getColumnIndex(KEY_ID)))
                item = cursor.getString(cursor.getColumnIndex(KEY_ITEM))
                hour = cursor.getInt(cursor.getColumnIndex(KEY_HOUR))
                min = cursor.getInt(cursor.getColumnIndex(KEY_MIN))
                date = cursor.getString(cursor.getColumnIndex(KEY_DATE))

                val reminder =
                    reminderHistory(id = id, item = item, hour = hour, min = min, date = date)
                rHistList.add(reminder)
            } while (cursor.moveToNext())
        }
        cursor.close()
        return rHistList
    }
                ...

The following error line

at com.example.reminders.FeedReaderDbHelper.viewReminder(DatabaseHandler.kt:61)

Refers to the line val db = this.readableDatabase

I am unsure if the problem lies with the context being null, (which is of the class) or the database. Please do offer any advice or comments regarding this. Thank you.


Solution

  • You are calling historyActivity in the wrong way, Try to open activity using intent. Try to implement using following code.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.history_main)
        createNotificationChannel()
        alarmService = AlarmService(this)
        val intent = Intent(this, HistoryActivity::class.java)
        startActivity(intent)
    }