Android中的多表SQLite数据库适配器?

我正在阅读Android SQLite NotePad教程,该教程引用了创build一个DB Adapter类来创build和访问数据库表。 在处理多表SQLite数据库时,是否最好为每个表创build一个不同的适配器类,或为整个Android应用程序创build一个数据库适配器类?

我的应用程序使用多个表,我希望不必有一个巨大的适配器类。 但问题是,每个适配器中的每个记事本示例都有一个SQLiteOpenHelper的嵌套子类。 当访问第一个表时,一切工作正常。 当我然后尝试访问第二个tble(从不同的活动)我的应用程序崩溃。

起初,我认为崩溃是由版本问题引起的,但现在两个适配器都有相同的数据库版本,并且仍然崩溃。

以下是该表的一个DB适配器的示例。 其他适配器都遵循相同的格式,具有不同的实现。

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$ } } 

当访问第一个适配器(在这种情况下是usersinfo)时,一切都按预期工作。 比方说,我有另一个友好信息适配器遵循上述相同的结构,当它被不同的活动访问时,似乎在我看来,SQLiteOpenHelper的嵌套子类将尝试再次创build数据库。 显然有些事情是错误的,因为在这种情况下,我的应用程序崩溃。

那么Android中的标准做法是创build一个庞大的数据库适配器,而不是每个表单独的适配器?

这是我最终实现的解决scheme。 这是从Commonsware书中获得的信息混搭,以及一些networking上的东西,我希望我书签因为我想给信贷:

对于我需要从数据库中提取的每种types的数据,我创build一个“适配器”类(不是从任何东西)。 这些适配器类包含访问该信息的数据库所需的所有方法。 例如,如果我在我的数据库中有三个表:

  1. 汽车
  2. 摩托车

我将有三个类似于以下的适配器(我只是把一个作为一个演示,但每个想法是相同的):

 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; } } 

所以,如果你想象我有每个表的这些类“适配器”之一。

当我的应用程序启animation面启动时,我使用了Android初学者提供的技术:为Android创build多个SQLite表

所以我的主DBAdapter(它负责在一个数据库中创build所有的表)看起来像这样:

 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(); } } 

DBAdapter类只在应用程序第一次启动时被调用,唯一的责任是创build/升级表。 对数据的所有其他访问都是通过单独的“适配器”类来完成的。 我发现这个工作完美,并没有创build我前面提到的版本问题。

希望这可以帮助。

有同样的问题,尝试了很多解决scheme,finnaly我做了一个抽象的方法构build数据库结构,并扩展了表类的类。

这是我的数据库构造函数类,是摘要:

 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(); } } 

这是我的表类之一,其余的类实现相同,只需添加你喜欢的:

 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); } } 

希望我帮助。