SQLiteDatabase 在 AsyncTask 中打开数据库 (Android)
SQLiteDatabase Opening DB in AsyncTask (Android)
我的自定义 SQLiteOpenHelper class 中的一个方法在关闭数据库后尝试调用它时抛出 "attempt to re-open already closed object" 错误。我在 MainActivity 上的 onPause 中关闭了我的数据库,然后我确保在调用数据库上的方法之前检查它们是否打开。
这是数据库方法的代码,它在 AsyncTask 中。
public void insertData(ArrayList<SavedWifiHotspot> hotspots, ArrayList<MarkerOptions> markers) {
Log.d("insert LocationsDB", "Data inserted");
final SQLiteDatabase db = this.getWritableDatabase();
new AsyncTask<ArrayList<SavedWifiHotspot>, Void, Void>() {
@Override
protected Void doInBackground(ArrayList<SavedWifiHotspot>... hotspots) {
Log.d("insert LocationsDB", "Hotspot inserted");
ContentValues hotspotValues = new ContentValues();
for(SavedWifiHotspot hotspot : hotspots[0]) {
hotspotValues.put("Ssid", hotspot.getSsid());
hotspotValues.put("Password", hotspot.getPassword());
hotspotValues.put("LocationName", hotspot.getHotspotLoc());
hotspotValues.put("Lat", hotspot.getLatitude());
hotspotValues.put("Lng", hotspot.getLongitude());
db.insert(HOTSPOT_TABLE_NAME, null, hotspotValues);
}
return null;
}
}.execute(hotspots);
new AsyncTask<ArrayList<MarkerOptions>, Void, Void>() {
@Override
protected Void doInBackground(ArrayList<MarkerOptions>... markers) {
ContentValues markerValues = new ContentValues();
for(MarkerOptions marker: markers[0]) {
markerValues.put("LocationName", marker.getTitle());
markerValues.put("Lat", marker.getPosition().latitude);
markerValues.put("Lng", marker.getPosition().longitude);
db.insert(LOCATION_TABLE_NAME, null, markerValues);
}
return null;
}
}.execute(markers);
}
这是调用方法的代码:
public void updateLocDB() {
if(!db.isOpen()) {
db = locDB.getReadableDatabase();
}
if(!wifiHotspots.isEmpty() && !markers.isEmpty()) {
locDB.clearData();
locDB.insertData(wifiHotspots, markers);
}
}
Logcat 输出:
FATAL EXCEPTION: AsyncTask #1
Process: com1032.cw2.fm00232.fm00232_assignment2, PID: 368
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalStateException: attempt to re-open an
already-closed object: SQLiteDatabase:/data/data/com1032.cw2.fm00232.fm00232_assignment2/databases/locationsDB
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1659)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1605)
at com1032.cw2.fm00232.fm00232_assignment2.LocationsDB.doInBackground(LocationsDB.java:89)
at com1032.cw2.fm00232.fm00232_assignment2.LocationsDB.doInBackground(LocationsDB.java:75)
at android.os.AsyncTask.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
我已经搜索了几个小时,但找不到任何可以帮助我解决这个问题的东西。任何帮助将不胜感激。
清除数据代码:
public void clearData() {
Log.d("clear LocationsDB", "Tables cleared");
db = this.getReadableDatabase();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
String dropHSTable = "DROP TABLE IF EXISTS "
+ HOTSPOT_TABLE_NAME + ";";
String dropLocTable = "DROP TABLE IF EXISTS "
+ LOCATION_TABLE_NAME + ";";
db.execSQL(dropHSTable);
db.execSQL(dropLocTable);
createTables(db);
return null;
}
}.execute();
}
如果 locDB.clearData();
也是异步的,它可能会通过打开与 locDB.insertDatalocDB.insertData
.
相同的 SQLite 数据库的连接而导致该错误
据我了解,您正在同时执行两个异步任务。 creating/opening 两个任务中的 SQLite 数据库连接。这造成了问题。
因为,无法创建 SQLite 数据库的两个连接。因为 SQLite 是线程安全的,所以一次只能有一个线程执行 read/write 操作。
除非你不使用WAL(Write Ahead Logging),否则你不能在SQLite上并发执行读写操作。关注此了解更多信息
我的自定义 SQLiteOpenHelper class 中的一个方法在关闭数据库后尝试调用它时抛出 "attempt to re-open already closed object" 错误。我在 MainActivity 上的 onPause 中关闭了我的数据库,然后我确保在调用数据库上的方法之前检查它们是否打开。
这是数据库方法的代码,它在 AsyncTask 中。
public void insertData(ArrayList<SavedWifiHotspot> hotspots, ArrayList<MarkerOptions> markers) {
Log.d("insert LocationsDB", "Data inserted");
final SQLiteDatabase db = this.getWritableDatabase();
new AsyncTask<ArrayList<SavedWifiHotspot>, Void, Void>() {
@Override
protected Void doInBackground(ArrayList<SavedWifiHotspot>... hotspots) {
Log.d("insert LocationsDB", "Hotspot inserted");
ContentValues hotspotValues = new ContentValues();
for(SavedWifiHotspot hotspot : hotspots[0]) {
hotspotValues.put("Ssid", hotspot.getSsid());
hotspotValues.put("Password", hotspot.getPassword());
hotspotValues.put("LocationName", hotspot.getHotspotLoc());
hotspotValues.put("Lat", hotspot.getLatitude());
hotspotValues.put("Lng", hotspot.getLongitude());
db.insert(HOTSPOT_TABLE_NAME, null, hotspotValues);
}
return null;
}
}.execute(hotspots);
new AsyncTask<ArrayList<MarkerOptions>, Void, Void>() {
@Override
protected Void doInBackground(ArrayList<MarkerOptions>... markers) {
ContentValues markerValues = new ContentValues();
for(MarkerOptions marker: markers[0]) {
markerValues.put("LocationName", marker.getTitle());
markerValues.put("Lat", marker.getPosition().latitude);
markerValues.put("Lng", marker.getPosition().longitude);
db.insert(LOCATION_TABLE_NAME, null, markerValues);
}
return null;
}
}.execute(markers);
}
这是调用方法的代码:
public void updateLocDB() {
if(!db.isOpen()) {
db = locDB.getReadableDatabase();
}
if(!wifiHotspots.isEmpty() && !markers.isEmpty()) {
locDB.clearData();
locDB.insertData(wifiHotspots, markers);
}
}
Logcat 输出:
FATAL EXCEPTION: AsyncTask #1
Process: com1032.cw2.fm00232.fm00232_assignment2, PID: 368
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalStateException: attempt to re-open an
already-closed object: SQLiteDatabase:/data/data/com1032.cw2.fm00232.fm00232_assignment2/databases/locationsDB
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1659)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1605)
at com1032.cw2.fm00232.fm00232_assignment2.LocationsDB.doInBackground(LocationsDB.java:89)
at com1032.cw2.fm00232.fm00232_assignment2.LocationsDB.doInBackground(LocationsDB.java:75)
at android.os.AsyncTask.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
我已经搜索了几个小时,但找不到任何可以帮助我解决这个问题的东西。任何帮助将不胜感激。
清除数据代码:
public void clearData() {
Log.d("clear LocationsDB", "Tables cleared");
db = this.getReadableDatabase();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
String dropHSTable = "DROP TABLE IF EXISTS "
+ HOTSPOT_TABLE_NAME + ";";
String dropLocTable = "DROP TABLE IF EXISTS "
+ LOCATION_TABLE_NAME + ";";
db.execSQL(dropHSTable);
db.execSQL(dropLocTable);
createTables(db);
return null;
}
}.execute();
}
如果 locDB.clearData();
也是异步的,它可能会通过打开与 locDB.insertDatalocDB.insertData
.
据我了解,您正在同时执行两个异步任务。 creating/opening 两个任务中的 SQLite 数据库连接。这造成了问题。
因为,无法创建 SQLite 数据库的两个连接。因为 SQLite 是线程安全的,所以一次只能有一个线程执行 read/write 操作。
除非你不使用WAL(Write Ahead Logging),否则你不能在SQLite上并发执行读写操作。关注此了解更多信息