我在我的 android 应用程序的 Crashlytics-Logs 中看到以下代码中的 NullPointerException:
try {
mSQLDBreader = this.getReadableDatabase();
} catch (SQLException e) {
if (mSQLDBreader != null) {
mSQLDBreader.close();
mSQLDBreader = this.getReadableDatabase();
}
}
mSQLDBreader... // NPE
由于之前的开发人员已不可用,我不知道为什么尝试了两次,但是代码有时似乎可以工作,但通常不会。此调用返回 null 的原因可能是什么?
似乎这仅发生在 2.3.x 设备上,在我的崩溃日志中,所有受影响的设备都是 2.3.5 和 2.3.6。
最佳答案
您是否有自己创作的线程?一些可能通过另一种方法重置 mSQLDBreader
的代码。也许那个线程在你使用它之前偶尔会运行并破坏 mSQLDBreader 的值?
您是否曾在运行 2.3.x 的模拟器上目睹过这种情况?
我查看了 google 的 getReadableDatabase 代码,但没有看到它可以返回 null 的方法。如果您有兴趣,下面是血腥的详细信息。根据我所看到的,我怀疑您的代码中存在多线程错误,或者您测试的设备制造商对 android 代码的自定义引入的错误(如果这甚至是合理的)。
血腥细节 所有通过 getReadableDatabase 的路径在创建返回对象后调用方法。因此,此时该值不能为空。否则 NPE 将从内部升起。
这是 getReadableDatabase 的 2.3.6 代码 fragment 。实际来源可在 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 的 close 方法,都带有同步标记,因此如果您有多个线程调用这些方法,则一种方法无法破坏另一种方法的状态同时..
关于android - getReadableDatabase 经常,但并不总是返回 null,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25917800/