Search code examples
androidsqlitesqliteopenhelper

SQLiteOpenHelper onCreate running twice?


In my database handler class (extends SQLiteOpenHelper) I have the onCreate() Method:

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_TABLE_TASKS); 
    db.execSQL(CREATE_TABLE_CONTACTS);
}

Sometimes (very rarely, but still) this leads to a crash because apparently the first table already exists. Obviously I can (and did) add IF NOT EXISTS to the statement to fix this, but what I want to know is what are the circumstances where onCreate() would be run if the table already exists. That is ordinarily not supposed to happen, so I've probably messed something up, but I can't figure out what.


Solution

  • I want to know is what are the circumstances where onCreate() would be run if the table already exists

    Race condition: More than one thread trying to get a hold of the database via getReadableDatabase() or getWritableDatabase().

    Specifically if the threads are interleaved between getVersion() and setVersion() in the code:

    242            final int version = db.getVersion();
    243            if (version != mNewVersion) {
    ...
    251                    if (version == 0) {
    252                        onCreate(db);
    253                    } else {
    254                        if (version > mNewVersion) {
    255                            onDowngrade(db, version, mNewVersion);
    256                        } else {
    257                            onUpgrade(db, version, mNewVersion);
    258                        }
    259                    }
    260                    db.setVersion(mNewVersion);
    

    There's a non-trivial amount of processing and some disk I/O involved so it's not hard for two threads to end up in this race.

    Possible solutions:

    • Synchronization: Use Java synchronization primitives to prevent the other thread from attempting to create the database at the same time.

    • Singleton with synchronization. Ensure there's only one database helper.

    • Access the database only in a single thread.