1

我在这行代码中得到一个零星的(约 30 次中的 1 次)NullPointerException。而且我不知道它来自哪里以及如何防止它。

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

mDb 是一个 SQliteDatabase 对象,Close 函数被实现到一个 Helper 类中。

我在做什么:我想用 AsyncTask 在 SQliteDatabase 中处理一个复杂的查询。这是 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): at android.os.AsyncTask$3.done(AsyncTask.java:278)
03-26 00:44:20.520: E/AndroidRuntime( 6442): 在 java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 03-26 00:44:20.520: E/AndroidRuntime(6442): 在 java.util.concurrent.FutureTask.setException(FutureTask .java:124)
03-26 00:44:20.520: E/AndroidRuntime(6442): 在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
03-26 00:44:20.520: E/AndroidRuntime(6442) : 在 java.util.concurrent.FutureTask.run(FutureTask.java:137)
03-26 00:44:20.520: E/AndroidRuntime(6442): 在 android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java: 208)
03-26 00:44:20.520: E/AndroidRuntime(6442): 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-26 00:44:20.520: E/AndroidRuntime(6442) : 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-26 00:44:20.520: E/AndroidRuntime(6442): 在 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): 在 android.database.sqlite.SQLiteDatabase.closeDatabase(SQLiteDatabase.java:1156) 03-26 00:44:20.520: E/AndroidRuntime(6442): 在android.database.sqlite.SQLiteDatabase.close(SQLiteDatabase.java:1105) 03-26 00:44:20.520: E/AndroidRuntime(6442): 在 de.kialelem.trainer.DbHelper.close(DbHelper.java:676) 03 -26 00:44:20.520: E/AndroidRuntime(6442): 在 de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask.doInBackground(ViewContentDatabaseListFragment.java:48) 03-26 00:44:20.520: E/AndroidRuntime(6442):在 de.kialelem.trainer.ViewContentDatabaseListFragment$processCursorTask.doInBackground(ViewContentDatabaseListFragment.java:1) 03-26 00:44:20.520: E/AndroidRuntime(6442): 在 android.os.AsyncTask$2.call(AsyncTask.java:264 ) 03-26 00:44:20。520: E/AndroidRuntime(6442): 在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
03-26 00:44:20.520: E/AndroidRuntime(6442): ... 还有 5 个

4

2 回答 2

2

目前尚不完全清楚您的close()上述方法属于哪个类。无论如何,您要调用mDb.close()两次:一次 inclose()和一次 in doInBackground()

异常是在里面发生SQLiteDatabase.closeDatabase()的,所以不是mDb你的存在造成的null

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

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

于 2012-03-26T11:58:51.770 回答
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);
}
}
于 2012-06-07T21:38:08.860 回答