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