Intermittent NPE when entering data in SQLite

I get a NullPointerException when I insert values โ€‹โ€‹into a SQLite table on Android, and I don't understand why. I am testing ContentValues โ€‹โ€‹and the database instance for null.

This is the insert code:

public void insertOrIgnore(ContentValues values) { SQLiteDatabase db = this.dbHelper.getWritableDatabase(); try { //I added these null value checks to stop NPE, but doesn't help. if (values != null && db != null) { db.insertWithOnConflict(TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE); } } catch (SQLiteException e) { } finally { if (db != null) { db.close(); } } } 

Where

 public static final String TABLE = "albums"; 

In most cases, this code works with data added to the database, as expected. However, sometimes it rarely generates an error below. A stack trace from ACRA, and I could not isolate under what conditions this error occurs. I am looking for pointers as to why this is happening and what are the conditions. My SQLite knowledge is a beginner level.

 java.lang.NullPointerException at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290) at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96) at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2025) at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1965) at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690) at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605) at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:247) at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:112) at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844) at com.mydomain.myapp.albums.AlbumsData.insertOrIgnore(AlbumsData.java:89) 

Line 89 is the call to db.insertWithOnConflict (...) shown above.

I'm not looking for an answer with the full code, but rather a pointer and an explanation of what is going wrong, so I can fix it myself.

EDIT: The stack trace shows that NPE comes from SQLiteStatement (v 4.03) line 290:

  setNativeHandle(mDatabase.mNativeHandle); 

So it seems that the database instance is null. How can it become null during a transaction when I checked the null value at the start of a transaction?

+4
source share
2 answers

As mentioned here, the SQLiteDatabase close () function that throws a NullPointerException on multiple threads

The reason for your error may be that you are at some point closing the database. Perhaps at the same time, when a task that failed, was not completed.

I followed stacktrace several times, and it is something like this:

  • AlbumsData.insertOrIgnore(AlbumsData.java:89)
    You call insertWithOnConflict , which creates the resulting sql string ( "INSERT OR IGNORE INTO..." ), then wraps this along with the values โ€‹โ€‹from your ContentValues in SQLiteStatement .
  • SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844) - the resulting statement must be executed now
  • SQLiteStatement.executeInsert(SQLiteStatement.java:112) - before the actual insert occurs, the database must receive a lock.
  • SQLiteStatement.acquireAndLock(SQLiteStatement.java:247) - here some checks occur, the database object until I see the zero point. The code decides that it should start the transaction. The database object itself, as far as I can see, is not locked at this point.
  • SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605) - just a redirect
  • SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690) - after some checks (not sure if the database should exist here), it will try to execute execSQL("BEGIN IMMEDIATE;")
  • SQLiteDatabase.execSQL(SQLiteDatabase.java:1965) - just go
  • SQLiteDatabase.executeSql(SQLiteDatabase.java:2025) - creates another SQLiteStatement from "BEGIN IMMEDIATE; SQLiteStatement This should be done now
  • SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96) - starts by checking for database locks, everything seems to be in order, and the database should not be null here. Then the instruction is executed and, finally, the database should be unlocked again.
  • SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290) - Cleans up some things and ultimately fails with NPE because the database is null .

Line numbers do not match, so there are probably vendor modifications / additions in this code.

As you can see, the code drops to the actual use of the data you provided. He was going to do

 BEGIN TRANSACTION IMMEDIATE; -- crash INSERT INTO table (...) VALUES (...); -- (end transaction) 

This makes it, in my opinion, a framework. The database object that is internally processed there should not be null somewhere down the line, especially when it seems that it was no longer null on the stack.

I also think it is possible that the reason for this may be another hidden exception. There are many try { /* do stuff */ } finally { /* clean up */ } blocks inside the code, and the finally part will execute even if the try part try an exception. Now, the finally block can raise another exception, and the result will be AFAIK so that the original exception is replaced with the new exception from the finally block.

Especially executeUpdateDelete() is similar to

 try { acquireAndLock(WRITE); // actual statement execution } finally { releaseAndUnlock(); } 

if the database is closed at this point, acquireAndLock or any code in the try part may fail, and this may leave the database object null , causing releaseAndUnlock to crash again. You should get the same stack.

Also, do not make empty catch blocks, such as catch (SQLiteException e) { /* empty */ } . Record them with ACRA, if possible / you will not.

+2
source

This NPE comes from a custom ROM, as the Android source code points to different methods than what you get in LogCat. What I do for such cases is that: if the speed of these exceptions is very rare, I ignore them, because it is difficult to understand which user ROM works on the phone, and it is more difficult to get the source code of this user ROM where the problem is.

Few users use custom ROMs, so if you have carefully tested your application on different phones with different SDKs, and the rate of Exceptions you receive is not so significant, you can ignore them. Otherwise, you can shoot in the dark and talk about what might be in this custom ROM that causes NPE (personally, I think this is not worth the effort).

+1
source

All Articles