views:

69

answers:

1

I was reading the Android SQLite NotePad tutorial that referenced creating a DB Adapter class to create and access a DB table. When dealing with a multi-table SQLite Database, is it best practice to create a different Adapter Class for each table or create a single DB Adapter class for the entire Android Application?

My application uses multiple tables and I was hoping not to have to have a single massive adapter class. the problem, however, is that I have a nested subclass of SQLiteOpenHelper per the NotePad Example within each adapter. When the first table is accessed, everything works fine. When I then try to access the second tble(from a different activity) my app crashes.

At first, I thought the crash was being caused by a versioning issue, but both adapters now have the same database version and it's still crashing.

Here's an example of one of the DB Adapters for the table. The other adapters all follow the same format with varying implementations.

public class InfoDBAdapter {
    public static final String ROW_ID = "_id";
    public static final String NAME = "name";

    private static final String TAG = "InfoDbAdapter";
    private static final String DATABASE_NAME = "myappdb";
    private static final String DATABASE_TABLE = "usersinfo";
    private static final int DATABASE_VERSION = 1;


    private static final String DATABASE_CREATE = "create table usersinfo (_id integer primary key autoincrement, "
            + NAME
            + " TEXT," + ");";

    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;

    private final Context mCtx;

    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {

            db.execSQL(DATABASE_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to " //$NON-NLS-1$//$NON-NLS-2$
                    + newVersion + ", which will destroy all old data"); //$NON-NLS-1$
            //db.execSQL("DROP TABLE IF EXISTS usersinfo"); //$NON-NLS-1$
            onCreate(db);
        }
    }


    public InfoDBAdapter(Context ctx) {
        this.mCtx = ctx;
    }


    public InfoDBAdapter open() throws SQLException {
        this.mDbHelper = new DatabaseHelper(this.mCtx);
        this.mDb = this.mDbHelper.getWritableDatabase();
        return this;
    }

    /**
     * close return type: void
     */
    public void close() {
        this.mDbHelper.close();
    }


    public long createUser(String name) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(NAME, name);
        return this.mDb.insert(DATABASE_TABLE, null, initialValues);
    }


    public boolean deleteUser(long rowId) {

        return this.mDb.delete(DATABASE_TABLE, ROW_ID + "=" + rowId, null) > 0; //$NON-NLS-1$
    }


    public Cursor fetchAllUsers() {

        return this.mDb.query(DATABASE_TABLE, new String[] { ROW_ID,
                NAME}, null, null, null, null, null);
    }


    public Cursor fetchUser(long rowId) throws SQLException {

        Cursor mCursor =

        this.mDb.query(true, DATABASE_TABLE, new String[] { ROW_ID, NAME}, ROW_ID + "=" + rowId, null, //$NON-NLS-1$
                null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;

    }


    public boolean updateUser(long rowId, String name) {
        ContentValues args = new ContentValues();
        args.put(NAME, name);
        return this.mDb
                .update(DATABASE_TABLE, args, ROW_ID + "=" + rowId, null) > 0; //$NON-NLS-1$
    }
}

When the first adapter, in this case usersinfo, is accessed, everything works as expected. Let's say I have another adapter for friend info that follows the same structure as above, when it is accessed by a different activity, it would seem to me that the nested subclass of SQLiteOpenHelper would attempt to create the database again. Obviously something is wrong because in that scenario, my app crashes.

So is the standard practice within Android to create a single mammoth db adapter instead of individual adapters per table?

A: 

When dealing with a multi-table SQLite Database, is it best practice to create a different Adapter Class for each table or create a single DB Adapter class for the entire Android Application?

To assist anyone else reading this question, here, "Adapter" is not a subclass of android.widget.Adapter, but an arbitrary other Java class.

however, is that I have a nested subclass of SQLiteOpenHelper per the NotePad Example within each adapter

You want to have one SQLiteOpenHelper per database.

When I then try to access the second tble(from a different activity) my app crashes.

Use adb logcat, DDMS, or the DDMS perspective in Eclipse to examine LogCat and see the stack trace associated with your crashes.

So is the standard practice within Android to create a single mammoth db adapter instead of individual adapters per table?

There is no "standard practice" regarding creating arbitrary Java classes, like your "Adapter" class.\

CommonsWare
@CommonsWare: You say `There is no "standard practice" regarding creating arbitrary Java classes, like your "Adapter" class`. But are there any _best practices_ w.r.t. creating and managing larger databases with several tables?
Nailuj
@Nailuj: That is impossible to answer in the abstract.
CommonsWare
@CommonsWare: not sure I understand what you mean by "in the abstract" (English not being my native language). But how can it be impossible (for someone with a bit of knowledge and experience with developing Android apps) to point out some best practices in how to handle database management when dealing with many tables? It doesn't have to be much more than sharing some of ones own experiences and tips in the area...
Nailuj
@Nailuj: The "best practices" will vary by database structure.
CommonsWare
@CommonsWare: ok, perhaps "best practices" isn't the best word to use in this case. Still, it should be possible to give some general advice for a good "pattern" to use when working with a multi-table database on Android, right? And I assume that _that_ is what the OP (and myself for that matter) was wondering about...
Nailuj
@Nailuj: The "good pattern" will vary by database structure. It will also vary by how you are using the database structure (populating ListViews? converting to JSON for submission to a Web service? wrapping in a `ContentProvider` for the purpose of supplying search suggestions to the Android search framework?). It may also vary by who is using the database structure (just Activities? Services? Content providers?). It may also vary by other dependencies (code reuse with another app? with another OS?).
CommonsWare
Perhaps the part that throwing me is that the examples show the SQLiteOpenHelper with table creation code. db.execSql being passed a string from the Adapter(arbitrary) wrapper class. In a more general framework, would these table creation strings just nee to be passed into the OpenHelper? Is there an example somewhere where this type of framework is available for view? If the SQLiteOpenHelper is aware of external classes (ie the individual Adapter Classes) then its coupled (I dont like coupling).
Shawn Yale
What implementation would need to be in place to "register" the table creation code with the SQLiteOpenHelper? Or would this even be necessary? I'm new to SQLite but not to db and I'm seeing code execution within the SQLiteOpenHelper that actually creates the tables. For example the onCreate and onUpgrade above. With a single SQLiteOpenHelper, would the table creation be encapsulated away from each adapter class so that the only thing the adapter classes did was instantiate a SQLiteOpenHelper and call open/close? With all other retrieval methods being contained within the adapter?
Shawn Yale