24

My first time asking a question here, so be gentle, Lol.

Anyway. Ive been working on an Android and my latest build ran flawlessly.. Until yesterday, when IT gave me a new workstation. Since getting this new workstation, I keep getting the following error:

04-11 17:34:53.282: E/AndroidRuntime(789): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.blueharvest/com.example.blueharvest.SettingsActivity}: java.lang.IllegalStateException: getDatabase called recursively

If it helps, I am running this in a virtual device, using platform 4.2.2 and API level 17.

I am really hoping that someone can shed some light on this error, so I can stop ripping my hair out, Lol.

If any other information is needed, please let me know.

Thanks so much,

Brad.

EDIT: Added more of the logcat

04-11 19:25:08.668: E/AndroidRuntime(2748): FATAL EXCEPTION: main
04-11 19:25:08.668: E/AndroidRuntime(2748): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.blueharvest/com.example.blueharvest.SettingsActivity}: java.lang.IllegalStateException: getDatabase called recursively
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.os.Looper.loop(Looper.java:137)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread.main(ActivityThread.java:5041)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at java.lang.reflect.Method.invokeNative(Native Method)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at java.lang.reflect.Method.invoke(Method.java:511)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at dalvik.system.NativeStart.main(Native Method)
04-11 19:25:08.668: E/AndroidRuntime(2748): Caused by: java.lang.IllegalStateException: getDatabase called recursively
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:204)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at com.example.blueharvest.DatabaseHandler.setDefaultLabel(DatabaseHandler.java:90)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at com.example.blueharvest.DatabaseHandler.onCreate(DatabaseHandler.java:82)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:188)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at com.example.blueharvest.DatabaseHandler.populateFields(DatabaseHandler.java:196)
 04-11 19:25:08.668: E/AndroidRuntime(2748):    at com.example.blueharvest.SettingsActivity.onCreate(SettingsActivity.java:45)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.Activity.performCreate(Activity.java:5104)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
04-11 19:25:08.668: E/AndroidRuntime(2748):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
04-11 19:25:08.668: E/AndroidRuntime(2748):     ... 11 more

EDIT: Added code causing the error. setDefaultLabel() is the culprit.

@Override
public void onCreate(SQLiteDatabase db) {
    // Create tables        
    db.execSQL(CREATE_CATEGORIES_TABLE);        
    db.execSQL(CREATE_CHRGDATA_TABLE);
    db.execSQL(CREATE_SETTINGS_TABLE);
    setDefaultLabel();
}

/**
 * 
 */

public void setDefaultLabel() {
    // create default label
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(KEY_NAME, "Default");
    db.insert(TABLE_LABELS, null, values);
}
Brad Bass
  • 361
  • 1
  • 4
  • 15
  • 2
    Posting an error without showing the code which is causing it isn't going to help anyone to help you. Also, post more of the logcat as there should be a "Caused by..." line. – Squonk Apr 11 '13 at 18:15
  • Well the code hadn't changed at all so I thought it not relevant in this particular case. The project itself is also quite large and not really sure where this error is coming from. The complete logcat has been added to the original post. The Caused by line states the same thing, getDatabase called recursively. Again, the only thing that has changed is the workstation.. Very confused. Anyway, thank you for the very quick reply. – Brad Bass Apr 11 '13 at 19:30
  • Ok... So apparently I was sleeping.. After reading through the logcat again, I noticed something that I hadn't before.. Ill admit I feel quite silly now for posting this. Anyway, the code causing this error has been added to original post. Still unsure why it would cause this issue, so any additional assistance would be great. Thanks again. B. – Brad Bass Apr 11 '13 at 19:58

2 Answers2

48

Try changing your setDefaultLabel() method to...

public void setDefaultLabel(SQLiteDatabase db)

...then in onCreate(...) simply pass the db parameter into it and get rid of this line...

SQLiteDatabase db = this.getWritableDatabase();

Your code should then look like this...

@Override
public void onCreate(SQLiteDatabase db) {
    // Create tables        
    db.execSQL(CREATE_CATEGORIES_TABLE);        
    db.execSQL(CREATE_CHRGDATA_TABLE);
    db.execSQL(CREATE_SETTINGS_TABLE);
    setDefaultLabel(db);
}

/**
 * 
 */

public void setDefaultLabel(SQLiteDatabase db) {
    // create default label
    ContentValues values = new ContentValues();
    values.put(KEY_NAME, "Default");
    db.insert(TABLE_LABELS, null, values);
}

The problem in your existing code is that onCreate(...) is being passed a reference to the open / writeable database but it then calls setDefaultLabel(...) which attempts to get another writeable reference to the database.

Squonk
  • 48,735
  • 19
  • 103
  • 135
  • Wow, thank you so much. I cant believe I missed that. I guess occasionally sleeping IS a good thing, Lol. Anyway, no longer getting the error, although its not exactly working as I had hoped. Was trying to have a "default" record created when the db is created. Will have to go back to the drawing board. Thanks again for all the help. – Brad Bass Apr 11 '13 at 20:56
  • @BradBass : Well at least that's one error you now understand and don't have to worry about. Glad to help. Good luck and have fun. – Squonk Apr 11 '13 at 21:09
  • Doesn't this neglect the getWriteableDatabase method altogether? Is that method unnecessary? – AlleyOOP Dec 30 '13 at 22:45
  • 2
    @AlleyOOP : Sorry, I don't really understand what you're asking. The question is primarily about the use of the `SQLiteOpenHelper` class and more specifically at the point of creating it. The `onCreate(...)` method is only run when first creating the database and it is passed a reference to the open (but empty) database. The OP was then trying to get another reference to the database (using getWriteableDatabase) in `setDeffaultLabel()` which is what caused the problem. At other times if there is no current open database reference then that method does need to be called to get one. – Squonk Dec 31 '13 at 03:50
  • Oh I see, but you also got rid of the getWriteable in the onCreate. Is it unnecessary there as well? – AlleyOOP Dec 31 '13 at 14:43
  • 3
    @AlleyOOP : If you look at the code in the OP's question you'll see there never was a call to `getWriteableDatabase` in the `onCreate` method and, if there had been, it would have caused the same problem due to the fact the `db` parameter passed in to `onCreate` is already a reference to the database. – Squonk Dec 31 '13 at 19:07
  • Ok this is where I get mixed up. Would you mind taking a look at my post? It still hasn't been resolved http://stackoverflow.com/questions/20831925/how-to-use-a-get-method-for-a-sqlite-database-management-class-in-another-class/20832170?noredirect=1#comment31246119_20832170 – AlleyOOP Dec 31 '13 at 19:57
  • @Squonk first thanks for your great explanation, I have a question too, I try to close the database before calling the `setDefaultLabel(db);` on the `onCreate`, but this time I get another error message(**attempt to re-open an already-closed object**), but why!? – ucMedia May 12 '19 at 16:21
3

Here is my solution for this: In the Helper, I override 2 methods getWritableDatabase() and getReadableDatabase() like below: Notice that you should not close the database, it may be crashed.

    @Override
    public void onCreate(SQLiteDatabase db) {
        // All your code here .....

        // Add default value for all tables
        isCreating = true;
        currentDB = db;
        generateAllDefaultData();
        // release var
        isCreating = false;
        currentDB = null;
    }

    boolean isCreating = false;
    SQLiteDatabase currentDB = null;

    @Override
    public SQLiteDatabase getWritableDatabase() {
        // TODO Auto-generated method stub
        if(isCreating && currentDB != null){
            return currentDB;
        }
        return super.getWritableDatabase();
    }

    @Override
    public SQLiteDatabase getReadableDatabase() {
        // TODO Auto-generated method stub
        if(isCreating && currentDB != null){
            return currentDB;
        }
        return super.getReadableDatabase();
    }
Phuong
  • 1,153
  • 1
  • 10
  • 17