1

First of all, all similar postings here didn't help.

In an AsyncTask I check if the app startup is the very first startup at all, that means I check if there is a database at all. I want to do that by query from a table. This is what is being executed:

@Override
public List<Entity> loadAll(Entity markerEntity)
{
    Log.i(TAG, "trying to load all entities of type " + markerEntity.getTable());

    List<Entity> results = new LinkedList<Entity>();

    SQLiteDatabase db = defaultSQLiteOpenHelper.getWritableDatabase();

    Cursor cursor = db.query(markerEntity.getTable(), markerEntity.getAllColumns(), null, null, null, null, null);    
    cursor.moveToFirst();

    while (!cursor.isAfterLast())
    {
        Entity result = markerEntity.createNewInstance(cursor);
        results.add(result);

        cursor.moveToNext();
    }

    db.close();

    return results;
}

The crash with IllegalArgumentException: database not open happens on this line.

SQLiteDatabase db = defaultSQLiteOpenHelper.getWritableDatabase();

It happens exactly on the method (see below) createAllTables.

The documentation says:

Create and/or open a database that will be used for reading and writing. The first time this is called, the database will be opened and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int) and/or onOpen(SQLiteDatabase) will be called.

In my opinion it should execute my DefaultSQLiteOpenhelper and create all database tables, but it doesn't do that:

public class DefaultSQLiteOpenHelper extends SQLiteOpenHelper implements ISQLiteOpenHelper
{
    private static final String TAG = DefaultSQLiteOpenHelper.class.getSimpleName();

    private static final String DATABASE_NAME = "MY_DATABASE";
    private static final int DATABASE_VERSION = 1;

    @Inject
    public DefaultSQLiteOpenHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    //is called by the framework if the database doesn't exist
    @Override
    public void onCreate(SQLiteDatabase db)
    {
        Log.i(TAG, "no database found. Generating new database...");

        createAllTables(db);    
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
         Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
//       db.execSQL("DROP TABLE IF EXISTS " + TABLE_COMMENTS); ///TODO when upgrade
//       onCreate(db);
    }

    //The order must not be changed because sqlite doesn't allow
    //table modification. That means one cannot add constraints afterwards
    //which results in creating tables in a specific order
    private final void createAllTables(SQLiteDatabase db)
    {
        db.beginTransaction();

        //create lookups at first
        db.execSQL(TableFactory.createUsage());
        db.execSQL(TableFactory.createLanguage());

        db.execSQL(TableFactory.createAccount());
        db.execSQL(TableFactory.createPreferences());
        db.execSQL(TableFactory.createLanguageUsageRel());
        db.execSQL(TableFactory.createPantry());
        db.execSQL(TableFactory.createProduct());

        //populate lookups
        db.execSQL(DataFactory.populateUsage());
        db.execSQL(DataFactory.populateLanguage());

        db.setTransactionSuccessful();
        db.endTransaction();
        db.close();
    }
}

The question is, why does it not open a database? Documentation says it has to. I don't accept any dirty workaround as solution like opening the database manually or something. What exactly is wrong on my code? I can't believe it's a bug in Android.

Here is the stacktrace:

05-27 17:25:50.370: I/DefaultSQLiteOpenHelper(719): no database found. Generating new database... 05-27 17:25:50.400: W/dalvikvm(719): threadid=10: thread exiting with uncaught exception (group=0x40015560) 05-27 17:25:50.400: E/AndroidRuntime(719): FATAL EXCEPTION: AsyncTask

1 05-27 17:25:50.400: E/AndroidRuntime(719): java.lang.RuntimeException: An error occured while executing

doInBackground() 05-27 17:25:50.400: E/AndroidRuntime(719): at android.os.AsyncTask$3.done(AsyncTask.java:200) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.FutureTask.setException(FutureTask.java:125) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.FutureTask.run(FutureTask.java:138) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.lang.Thread.run(Thread.java:1019) 05-27 17:25:50.400: E/AndroidRuntime(719): Caused by: java.lang.IllegalStateException: database not open 05-27 17:25:50.400: E/AndroidRuntime(719): at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:555) 05-27 17:25:50.400: E/AndroidRuntime(719): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:137) 05-27 17:25:50.400: E/AndroidRuntime(719): at com.mydomain.android.base.persistence.PersistenceManager.loadAll(PersistenceManager.java:58) 05-27 17:25:50.400: E/AndroidRuntime(719): at com.mydomain.android.base.main.StartupTask.isFirstStartAfterInstallation(StartupTask.java:107) 05-27 17:25:50.400: E/AndroidRuntime(719): at com.mydomain.android.base.main.StartupTask.doInBackground(StartupTask.java:52) 05-27 17:25:50.400: E/AndroidRuntime(719): at com.mydomain.android.base.main.StartupTask.doInBackground(StartupTask.java:18) 05-27 17:25:50.400: E/AndroidRuntime(719): at android.os.AsyncTask$2.call(AsyncTask.java:185) 05-27 17:25:50.400: E/AndroidRuntime(719): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) 05-27 17:25:50.400: E/AndroidRuntime(719): ... 4 more

3
  • You might consider posting the stack trace. Commented May 27, 2013 at 17:40
  • @CommonsWare Here it is. Commented May 27, 2013 at 17:44
  • 1
    db.close() in onCreate() is not correct. Commented May 27, 2013 at 17:47

1 Answer 1

5

First, you are closing the database in createAllTables(). Never close the database from onCreate() or onUpgrade() of a SQLiteOpenHelper.

Second, your transaction logic is unnecessary in createAllTables(), as onCreate() is executed in a transaction. This is good, as your transaction logic is improperly implemented, anyway.

To clarify that latter comment, the right way to do transactions is:

try {
    db.beginTransaction();

    // SQL

    db.setTransactionSuccessful();
}
// optional catch block
finally {
    db.endTransaction();
}

You need endTransaction() to be called if there is a SQL exception -- your implementation skips this.

Sign up to request clarification or add additional context in comments.

4 Comments

@CommmonsWare Is it allowed to get a writableDatabase in an AyncTask ? I am tempted to say that it could cause a concurrent exception. Could you light me on this please ?
@CommmonsWare Thanks, what a stupid mistake. :) By the way: Do you mean with improperly implemented that this is the wrong way to do transaction handling (despite on this example where I don't need it)? (I do something similar in my save method).
@user2336315: "Is it allowed to get a writableDatabase in an AyncTask ?" -- not only is it allowed, but it is pretty much mandatory, as getWriteableDatabase() can do significant disk I/O if it has to create or update the database. "I am tempted to say that it could cause a concurrent exception." -- as you can see by looking at the source code, it synchronizes this work.
@CommonsWare Thanks, good to see that I already do it in my save method in this way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.