偶然的NullPointerException,尽管事实上,Object不是null

时间:2012-03-26 11:52:57

标签: android sqlite android-asynctask android-listfragment

我在这行代码中得到零星的(大约30次)NullPointerException。我不知道它来自何处以及如何防止它。

public void close() {
    if (mDb!=null)
        mDb.close();
}

mDb是一个SQliteDatabase对象,而Close函数是在Helper类中实现的。

我在做什么:我想在SQliteDatabase中使用AsyncTask处理复杂查询。 这是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);
    }
}

我在这里创建了这个AsyncTask(来自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)   失败:27 03-26 00:44:20.520:W / dalvikvm(6442):threadid = 12:   线程退出与未捕获的异常(组= 0x40a691f8)03-26   00:44:20.520:E / AndroidRuntime(6442):致命异常:AsyncTask#2
  03-26 00:44:20.520:E / AndroidRuntime(6442):   java.lang.RuntimeException:执行时发生错误   doInBackground()03-26 00:44:20.520:E / AndroidRuntime(6442):     在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):引起: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:667)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 个答案:

答案 0 :(得分:2)

上述close()方法所属的课程并不完全清楚。无论如何,您要拨打mDb.close()两次:一次在close(),一次在doInBackground()

例外情况发生在SQLiteDatabase.closeDatabase()内,因此mDb null引起的不是

作为一般规则,不要打扰关闭数据库。在应用启动时打开一次,并在整个应用中重复使用相同的连接。关闭它没有任何好处,因为SQLite的事务性质确保所有写入都尽可能早地提交到存储。

编辑:好的,我现在可以看到mDb在每种情况下都不同。无论如何,请听取我关于不关闭数据库的建议,问题就会消失。

答案 1 :(得分:1)

找到解决方案: 问题是DbHelper对象是在UI线程上创建的,但在asyncTask工作线程中关闭。 将.close()移动到onPostExecute()方法后,异常消失了。

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