简体   繁体   English

在AsyncTask中打开SQLiteDatabase数据库(Android)

[英]SQLiteDatabase Opening DB in AsyncTask (Android)

One of my methods in my custom SQLiteOpenHelper class throws an "attempt to re-open already closed object" error whenever I try to invoke it after closing the database. 每当我在关闭数据库后尝试调用它时,我的自定义SQLiteOpenHelper类中的方法之一都会引发“尝试重新打开已关闭的对象”错误。 I close my databases in onPause on my MainActivity, and then I make sure to check if they are open before invoking a method on the database. 我在MainActivity的onPause中关闭数据库,然后确保在调用数据库中的方法之前检查它们是否已打开。

This is the code for the database method, it is within an AsyncTask. 这是数据库方法的代码,它在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);
    }

This is the code used to call the method: 这是用于调用该方法的代码:

public void updateLocDB() {
        if(!db.isOpen()) {
            db = locDB.getReadableDatabase();
        }
        if(!wifiHotspots.isEmpty() && !markers.isEmpty()) {
            locDB.clearData();
            locDB.insertData(wifiHotspots, markers);
        }
    }

Logcat output: 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$3.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$1.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$1.doInBackground(LocationsDB.java:89)
  at com1032.cw2.fm00232.fm00232_assignment2.LocationsDB$1.doInBackground(LocationsDB.java:75)
  at android.os.AsyncTask$2.call(AsyncTask.java:288)
  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
  at android.os.AsyncTask$SerialExecutor$1.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)

I've been searching for a few hours, and can't find anything that helps me fix this problem. 我已经搜索了几个小时,找不到任何可帮助我解决此问题的内容。 Any help would be appreciated. 任何帮助,将不胜感激。

clearData code: clearData代码:

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();
    }

If the locDB.clearData(); 如果locDB.clearData(); is also asynchronous it can cause that error by having the connection open to the same SQLite database with the locDB.insertDatalocDB.insertData . 也是异步的,它可以通过使用locDB.insertDatalocDB.insertData打开与同一SQLite数据库的连接来导致该错误。

As per my understanding you are executing two asynchronous task at same time. 据我了解,您正在同时执行两个异步任务。 And creating/opening a SQLite DB connection in both tasks. 并在两个任务中创建/打开SQLite DB连接。 Which creates the problem. 这就造成了问题。

As, it is not possible to create two connections of SQLite DB. 因此,不可能创建两个SQLite DB连接。 Because SQLite is ThreadSafe, only one thread can perform read/write operation at a single time. 因为SQLite是ThreadSafe,所以只有一个线程可以一次执行读/写操作。

You can not perform read and write operations concurrently on SQLite until you do not use WAL(Write Ahead Logging). 您必须先不使用WAL(预先写入日志记录),才能在SQLite上同时执行读写操作。 Follow this for more info Concurrency in SQLite database 请遵循以下详细信息SQLite数据库中的并发

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM