I'm the author of an Android library project that is frequently included in other apps. I use a small SQLite database for storage, which is accessed via android.database.sqlite.SQLiteOpenHelper.
When the app starts, the database helper creates the database (if needed), calls dbHelper.getWritableDatabase(), and uses the returned dbHelper reference for all database access. Important to note:
- Only the helper has access to the SQLiteDatabase object that is created.
- I do not call SQLiteDatabase.close() on the database at any point. I know that is a frequent cause of this issue but that's not the case here.
-
The apps that use my library are frequently multi-threaded. Inserts are done in batches, which are synchronized thusly:
public class DatabaseHelper extends SQLiteOpenHelper { ... ... ... public void insertBatch(LinkedList<DatabaseRecord> writeQueue) { Iterator<DatabaseRecord> it = writeQueue.iterator(); synchronized (this) { try { this.open(); db.beginTransaction(); while (it.hasNext()) { DatabaseRecord record = it.next(); Long lDate = System.currentTimeMillis() / 1000; ContentValues initialValues = new ContentValues(); initialValues.put(aa, record.aa); initialValues.put(bb, record.bb); initialValues.put(cc, record.cc); initialValues.put(dd, lDate); db.insert(DBTBL, null, initialValues); } db.setTransactionSuccessful(); } catch (Exception e) { Utility.logError(logtag, "Error inserting batch record into database.", e); } finally { db.endTransaction(); // sometimes throws "already-closed" exception! this.close(); } } }
The problem, as you can see in the comment, is that the endTransaction() call sometimes throws:
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/http://ift.tt/1aLc7dx near/at android.database.sqlite.SQLiteClosable.acquireReference:55
Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/http://ift.tt/1aLc7dx
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:535)
at com.aaa.bbb.DatabaseHelper.insertBatch(DatabaseHelper.java:273)
at com.aaa.bbb.WriteQueue.flushQueue(WriteQueue.java:88)
at com.aaa.bbb.WriteQueue.run(WriteQueue.java:77)
This works 99.95% of the time. But, oddly, it fails in a small percentage of cases. In looking at the places where it fails, there is one consistency: there are other SQLite databases present. In these cases, there are other third-party libraries that are calling SQLiteDatabase.close() directly.
Is it possible that this is closing all of the database instances on the device? Is there even a way to do that?
Aucun commentaire:
Enregistrer un commentaire