sporadic NullPointerException despite the fact, that the Object is not null
-
26-05-2021 - |
سؤال
Im getting a sporadic (1 out of ~30 times) NullPointerException in this line of Code. and I have no Idea where it comes from and how to prevent it.
public void close() {
if (mDb!=null)
mDb.close();
}
mDb is a SQliteDatabase Object and the Close function is implemented into a Helper class.
What I am doing: I want to handle a complex query in that SQliteDatabase with an AsyncTask. Here is the code of the AsyncTask:
private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
private DbHelper mDb;
processCursorTask(DbHelper db) {
super();
mDb=db;
}
@Override
protected Dataset[] doInBackground(Integer... args) {
Dataset[] res=mDb.getCursorFiltered(args);
mDb.close();
return res;
}
protected void onPostExecute(Dataset[] result) {
setListView(result);
}
}
And I am creating this AsyncTask here (from a ListFragment):
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new processCursorTask(new DbHelper(this.getActivity()), mBaseDivision, mBaseValue, mSortOrder, mSortDir).execute();
}
03-26 00:44:20.489: E/SqliteDatabaseCpp(6442): sqlite3_close(0x3b2278) failed: 27 03-26 00:44:20.520: W/dalvikvm(6442): threadid=12: thread exiting with uncaught exception (group=0x40a691f8) 03-26 00:44:20.520: E/AndroidRuntime(6442): FATAL EXCEPTION: AsyncTask #2
03-26 00:44:20.520: E/AndroidRuntime(6442): java.lang.RuntimeException: An error occured while executing doInBackground() 03-26 00:44:20.520: E/AndroidRuntime(6442): at android.os.AsyncTask$3.done(AsyncTask.java:278)
03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
03-26 00:44:20.520: E/AndroidRuntime(6442): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-26 00:44:20.520: E/AndroidRuntime(6442): at java.lang.Thread.run(Thread.java:856) 03-26 00:44:20.520: E/AndroidRuntime(6442): Caused by: java.lang.NullPointerException
03-26 00:44:20.520: E/AndroidRuntime(6442): at android.database.sqlite.SQLiteDatabase.closeDatabase(SQLiteDatabase.java:1156) 03-26 00:44:20.520: E/AndroidRuntime(6442): at android.database.sqlite.SQLiteDatabase.close(SQLiteDatabase.java:1105) 03-26 00:44:20.520: E/AndroidRuntime(6442): at de.kialelem.trainer.DbHelper.close(DbHelper.java:676) 03-26 00:44:20.520: E/AndroidRuntime(6442): at de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask.doInBackground(ViewContentDatabaseListFragment.java:48) 03-26 00:44:20.520: E/AndroidRuntime(6442): at de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask.doInBackground(ViewContentDatabaseListFragment.java:1) 03-26 00:44:20.520: E/AndroidRuntime(6442): at android.os.AsyncTask$2.call(AsyncTask.java:264) 03-26 00:44:20.520: E/AndroidRuntime(6442): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
03-26 00:44:20.520: E/AndroidRuntime(6442): ... 5 more
المحلول 2
Found the solution: The Problem was that the DbHelper Object was created on the UI thread but closed in the asyncTask worker thread. After I moved the .close() into the onPostExecute() method the exception disappeared.
private class processCursorTask extends AsyncTask<Integer[], Void, Dataset[]> {
private DbHelper mDb;
processCursorTask(DbHelper db) {
super();
mDb=db;
}
@Override
protected Dataset[] doInBackground(Integer... args) {
Dataset[] res=mDb.getCursorFiltered(args);
return res;
}
protected void onPostExecute(Dataset[] result) {
mDb.close();
setListView(result);
}
}
نصائح أخرى
It's not entirely clear what class your close()
method above belongs to. In any event, you are calling mDb.close()
twice: once in close()
and once in doInBackground()
.
The exception is happening inside SQLiteDatabase.closeDatabase()
, so it's not caused by your mDb
being null
.
As a general rule, don't bother closing the database. Open it once on app startup, and reuse the same connection throughout your app. You get no benefit from closing it, since SQLite's transactional nature ensures all writes are committed to storage at the earliest opportunity anyway.
EDIT: OK, I can see now that the mDb
in each case is different. In any event, take my advice about not closing the DB, and the problem will go away.