我在我的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。
答案 0 :(得分:1)
你有自己创作的线程吗?一些可能通过其他方法重置mSQLDBreader
的代码。也许该线程在使用之前偶尔会运行并破坏mSQLDBreader的值?
你有没有在运行2.3.x的模拟器上见过这个?
我查看了google的getReadableDatabase代码,但我没有看到它可以返回null的方法。如果您有兴趣,请参阅下面的血腥细节。基于我所看到的,我怀疑你的代码中存在多线程错误,或者是你所测试设备的制造商对android代码的自定义引入的错误(如果这甚至是合理的话。)
Gory详细信息所有通过getReadableDatabase的路径在创建后都会在返回对象上调用方法。因此,该点的值不能为null。否则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的close方法都使用synchronize进行标记,因此如果您有多个线程,则一个方法无法废弃另一个方法的状态同时调用这些方法..
答案 1 :(得分:0)
我过去遇到过类似的问题。似乎继续关闭并打开数据库为我创建了这个问题。如果您使用的是SQLLiteOpenHelper
,除非您有充分的理由,否则不应该关闭数据库。请参阅CommonsWare回答here,其中说
SQLiteOpenHelper保留在您检索的数据库中 getReadableDatabase()/ getWritableDatabase(),重点是你 重用那个打开的SQLiteDatabase对象,特别是像你一样 跨多个线程工作。
答案 2 :(得分:0)
使用前打开dataBase
echo "<tr><td colspan='6'><small>There's no player on ban list</small></td></tr>";
}
while($data = $query->fetch())
{
echo "<tr><td>".$data['name']."</td>";
echo "<td>".$data['kill']."</td>";
echo "<td>".$data['death']."</td>";
$kd = $data['kill'] / $data['death'];
echo "<td>".$kd."</td></tr>";
}
?>