你有沒有對自己的創作有任何線索?一些代碼可能會通過另一種方法重置mSQLDBreader
。也許該線程偶爾運行並在使用之前破壞mSQLDBreader的值?
你有沒有在運行2.3.x的模擬器上目睹過這一點?
我看着谷歌的代碼getReadableDatabase,我沒有看到它可以返回null的方式。血腥細節如下,如果你有興趣。根據我所看到的,我會懷疑您的代碼中存在多線程錯誤,或者由您測試的設備的製造商對android代碼進行自定義所引入的錯誤(如果這甚至是合理的)。
Gory details通過getReadableDatabase的所有路徑在創建它之後調用返回對象上的方法。所以這個值不能爲零。否則,NPE將從內部升起。
以下是getReadableDatabase的2.3.6代碼片段。實際來源可在grepcode上找到。
public synchronized SQLiteDatabase getReadableDatabase() {
if (mDatabase != null && mDatabase.isOpen()) {
return mDatabase; // The database is already open for business
}
if (mIsInitializing) { /* snip throw ISE */ }
try {
return getWritableDatabase();
} catch (SQLiteException e) {
// snip : throws or falls through below
}
SQLiteDatabase db = null;
try {
mIsInitializing = true;
String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
// *** next line calls method on db. NPE would be here if db was null at this point. ***
if (db.getVersion() != mNewVersion) {
// snip throw.
}
onOpen(db);
Log.w(TAG, "Opened " + mName + " in read-only mode");
mDatabase = db;
return mDatabase;
} finally {
// snip : not relevant
}
}
請注意,getReadableDatabase通常只返回getWritableDatabase的結果。他看起來是這樣的:
public synchronized SQLiteDatabase getWritableDatabase() {
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
return mDatabase; // The database is already open for business
}
if (mIsInitializing) {
throw new IllegalStateException("getWritableDatabase called recursively");
}
// snip comment about locking
boolean success = false;
SQLiteDatabase db = null;
if (mDatabase != null) mDatabase.lock();
try {
mIsInitializing = true;
if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
db = mContext.openOrCreateDatabase(mName, 0, mFactory);
}
int version = db.getVersion(); // ** method called on result!
// snip block that has more method calls and never nulls out db
onOpen(db);
success = true;
return db;
} finally {
// snip
mDatabase = db;
// snip rest of finally block that isn't relevant.
}
}
最後,需要注意的是這兩種方法,以及SqliteOpenHelper的接近方法,標記有同步是很重要的,所以沒有辦法對一個方法垃圾桶如果你有多個線程調用這些方法在同一時間其他的狀態..