SQLiteDatabase close()函数在多个线程时导致NullPointerException

时间:2011-11-03 17:13:22

标签: android sqlite nullpointerexception

我在我的项目中发现Android上的SQLiteDatabase实现中的close()函数在运行打开数据库,插入数据然后关闭数据库的多个线程时抛出NullPointerException。除非我允许每个线程在插入数据库后关闭(),否则一切都会顺利运行。

以下是其中一个写线程看起来像

的示例
        ContentValues values = new ContentValues();
        values.put(CallDetailsStorageConstants.COLUMN_NAME_REMOTE_NAME_IDX, (String) "");
        values.put(CallDetailsStorageConstants.COLUMN_NAME_REMOTE_MEETINGID_IDX, (String) "");

        CalculonDatabase callDetailsOpenHelper = CalculonDatabase.getInstance(mContext);
        SQLiteDatabase dbw = callDetailsOpenHelper.getWritableDatabase();

        long rowid = 0;
        try {
            rowid = dbw.insertWithOnConflict(CallDetailsTable.CALL_DETAILS_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
        } catch (SQLiteConstraintException e) {
            e.printStackTrace();
        } finally {
            dbw.close();
        }

你可以看到最后调用close()。当运行多个线程时,我得到了这个例外。

11-03 03:39:26.128: E/AndroidRuntime(977): FATAL EXCEPTION: Thread-17
11-03 03:39:26.128: E/AndroidRuntime(977): java.lang.NullPointerException
11-03 03:39:26.128: E/AndroidRuntime(977):  at     android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:283)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1933)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1864)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:636)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:551)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:240)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:111)
11-03 03:39:26.128: E/AndroidRuntime(977):  at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1737)
11-03 03:39:26.128: E/AndroidRuntime(977):  at com.smash.DBWritingThread.run(DBWritingThread.java:50)

我的问题是为什么只有在使用close()函数时才会发生此错误?此外,是否可以在更晚的时间使用close()或者可能永远不会?

非常感谢有关此问题的任何提示。

4 个答案:

答案 0 :(得分:13)

我有你的答案!

永远不要关闭数据库。就这么简单。

确保每个应用程序只有一个,重复*,一个 Helper实例。与所有主题分享。

http://www.touchlab.co/blog/single-sqlite-connection/

以下是有关sqlite和锁定内部的更多信息:

http://www.touchlab.co/blog/android-sqlite-locking/

答案 1 :(得分:4)

你不需要打扰。请参阅this discussion,其中包括确认如果/当进程被终止时,系统根据需要关闭数据库。

来自Google员工的相关引言是:

  

在创建托管进程时创建内容提供程序,并且   只要这个过程一直存在,所以没有必要关闭   数据库 - 它将作为内核清理的一部分关闭   进程被终止时进程的资源。

答案 2 :(得分:1)

如果您直接在SQLite数据库上工作而不求助于内容提供者,我所看到的模式是在Application.onTerminate中关闭数据库,而Application实例存储单例数据库“适配器“,它将是一个包含SQLiteDatabase及其SQLiteOpenHelper

的对象

答案 3 :(得分:0)

看起来与此问题类似:SQLiteDatabase close()函数在多个线程时导致NullPointerException

您可能不需要调用database.close()