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 Databa
Here is the solution I eventually ended up implementing. It's kind of a mash-up from info gained in the Commonsware books, and some stuff around the web that I wish I bookmarked cause I want to give credit:
For each type of data that I need to pull from the db, I create an "adapter" class (not subclassed from anything). These adapter classes hold all of the methods necessary for accessing the db for that piece of info. For example, if I had three tables in my db:
I would have three adapters that would look similar to the following(I'm only putting in one as a demo, but the idea is the same for each):
public class CarsDBAdapter {
public static final String ROW_ID = "_id";
public static final String NAME = "name";
public static final String MODEL = "model";
public static final String YEAR = "year";
private static final String DATABASE_TABLE = "cars";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DBAdapter.DATABASE_NAME, null, DBAdapter.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx
* the Context within which to work
*/
public CarsDBAdapter(Context ctx) {
this.mCtx = ctx;
}
/**
* Open the cars database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException
* if the database could be neither opened or created
*/
public CarsDBAdapter 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();
}
/**
* Create a new car. If the car is successfully created return the new
* rowId for that car, otherwise return a -1 to indicate failure.
*
* @param name
* @param model
* @param year
* @return rowId or -1 if failed
*/
public long createCar(String name, String model, String year){
ContentValues initialValues = new ContentValues();
initialValues.put(NAME, name);
initialValues.put(MODEL, model);
initialValues.put(YEAR, year);
return this.mDb.insert(DATABASE_TABLE, null, initialValues);
}
/**
* Delete the car with the given rowId
*
* @param rowId
* @return true if deleted, false otherwise
*/
public boolean deleteCar(long rowId) {
return this.mDb.delete(DATABASE_TABLE, ROW_ID + "=" + rowId, null) > 0; //$NON-NLS-1$
}
/**
* Return a Cursor over the list of all cars in the database
*
* @return Cursor over all cars
*/
public Cursor getAllCars() {
return this.mDb.query(DATABASE_TABLE, new String[] { ROW_ID,
NAME, MODEL, YEAR }, null, null, null, null, null);
}
/**
* Return a Cursor positioned at the car that matches the given rowId
* @param rowId
* @return Cursor positioned to matching car, if found
* @throws SQLException if car could not be found/retrieved
*/
public Cursor getCar(long rowId) throws SQLException {
Cursor mCursor =
this.mDb.query(true, DATABASE_TABLE, new String[] { ROW_ID, NAME,
MODEL, YEAR}, ROW_ID + "=" + rowId, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
/**
* Update the car.
*
* @param rowId
* @param name
* @param model
* @param year
* @return true if the note was successfully updated, false otherwise
*/
public boolean updateCar(long rowId, String name, String model,
String year){
ContentValues args = new ContentValues();
args.put(NAME, name);
args.put(MODEL, model);
args.put(YEAR, year);
return this.mDb.update(DATABASE_TABLE, args, ROW_ID + "=" + rowId, null) >0;
}
}
So if you imagine I have one of these classes "adapters" for each table.
When my app splash screen starts, I use the technique presented Android For Beginners: Creating multiple SQLite Tables for Android
So my main DBAdapter (which is responsible for creating all of my tables in a single db) looks like this:
public class DBAdapter {
public static final String DATABASE_NAME = "stuffIOwn"; //$NON-NLS-1$
public static final int DATABASE_VERSION = 1;
private static final String CREATE_TABLE_CARS =
"create table cars (_id integer primary key autoincrement, " //$NON-NLS-1$
+ CarsDBAdapter.NAME+ " TEXT," //$NON-NLS-1$
+ CarsDBAdapter.MODEL+ " TEXT," //$NON-NLS-1$
+ CarsDBAdapter.YEAR+ " TEXT" + ");"; //$NON-NLS-1$ //$NON-NLS-2$
private static final String CREATE_TABLE_BOATS = "create table boats (_id integer primary key autoincrement, " //$NON-NLS-1$
+BoatsDBAdapter.NAME+" TEXT," //$NON-NLS-1$
+BoatsDBAdapter.MODEL+" TEXT," //$NON-NLS-1$
+BoatsDBAdapter.YEAR+" TEXT"+ ");"; //$NON-NLS-1$ //$NON-NLS-2$
private static final String CREATE_TABLE_CYCLES = "create table cycles (_id integer primary key autoincrement, " //$NON-NLS-1$
+CyclesDBAdapter.NAME+" TEXT," //$NON-NLS-1$
+CyclesDBAdapter.MODEL+" TEXT," //$NON-NLS-1$
+CyclesDBAdapter.YEAR+" TEXT"+ ");"; //$NON-NLS-1$ //$NON-NLS-2$
private final Context context;
private DatabaseHelper DBHelper;
private SQLiteDatabase db;
/**
* Constructor
* @param ctx
*/
public DBAdapter(Context ctx)
{
this.context = ctx;
this.DBHelper = new DatabaseHelper(this.context);
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_TABLE_CARS);
db.execSQL(CREATE_TABLE_BOATS);
db.execSQL(CREATE_TABLE_CYCLES);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion)
{
// Adding any table mods to this guy here
}
}
/**
* open the db
* @return this
* @throws SQLException
* return type: DBAdapter
*/
public DBAdapter open() throws SQLException
{
this.db = this.DBHelper.getWritableDatabase();
return this;
}
/**
* close the db
* return type: void
*/
public void close()
{
this.DBHelper.close();
}
}
The DBAdapter class only gets called when the app first starts and its only responsibility is to create/upgrade the tables. All other access to the data is done through the individual "adapter" class. I've found that this works perfectly and does not create the versioning issues that I mentioned earlier.
Hope this helps.
Had the same problem, tried many solutions, finnaly i made an abstract method wich constructs the database structure and has extended class for the table classes.
This is my Database constructor class and is Abstract:
public abstract class dbAdapter {
public static String DATABASE_NAME = "";
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_TABLE1 = "ContactName";
public static final String DATABASE_TABLE2 = "PhoneNumber";
public static DbHelper ourHelper;
public static Context ourContext;
public static SQLiteDatabase ourDatabase;
boolean ourConstructorBool = false;
boolean ourDB = false;
public static final String ContactNameTable = "CREATE TABLE "+DATABASE_TABLE1+" (" +
ContactNameAdapter.KEY_ROWID+" INTEGER PRIMARY KEY AUTOINCREMENT, " +
ContactNameAdapter.KEY_NAME+" TEXT, " +
ContactNameAdapter.KEY_BIRTH_DATE+" TEXT);";
public static final String PhoneNumberTable = "CREATE TABLE "+DATABASE_TABLE2+" (" +
PhoneNumberAdapter.KEY_NUMBER+" TEXT , " +
PhoneNumberAdapter.KEY_DESCRIPTION+" TEXT, " +
PhoneNumberAdapter.KEY_CONTACTID+" TEXT, " +
"FOREIGN KEY(" + PhoneNumberAdapter.KEY_CONTACTID +") REFERENCES " +
(ContactNameAdapter.DATABASE_TABLE)+"("+ContactNameAdapter.KEY_ROWID+") ON DELETE CASCADE"+
");";
static class DbHelper extends SQLiteOpenHelper{
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(ContactNameTable);
db.execSQL(PhoneNumberTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
db.execSQL("DROP TABLE IF EXISTS " + ContactNameAdapter.DATABASE_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + PhoneNumberAdapter.DATABASE_TABLE);
onCreate(db);
}
}
public dbAdapter(Activity a){
if(!ourConstructorBool == true){
ourContext = a;
DATABASE_NAME = a.getString(Asaf.com.contactsEX.R.string.DB_NAME);
ourConstructorBool = true;
}
}
public dbAdapter open() throws SQLException{
if(!ourDB == true){
ourHelper = new DbHelper(ourContext);
ourDB = true;
}
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close(){
if(ourDatabase.isOpen())
ourHelper.close();
}
}
And this is one of my table classes, the rest of the classes are implemented the same, just add as much as you like:
public class PhoneNumberAdapter extends dbAdapter{
public static final String KEY_NUMBER = "PhoneNumber";
public static final String KEY_DESCRIPTION = "Description";
public static final String KEY_CONTACTID = "ContactName_id";
public static final String DATABASE_TABLE = "PhoneNumber";
public PhoneNumberAdapter(Activity a){
super(a);
}
public long createEntry(String number, String description,long id){
// TODO Auto-generated method stub
ContentValues cv = new ContentValues();
cv.put(KEY_NUMBER, number);
cv.put(KEY_DESCRIPTION, description);
cv.put(KEY_CONTACTID, id);
return ourDatabase.insert(DATABASE_TABLE, null,cv);
}
}
Hope I helped.