多个表的SQLite数据库适配器(收费)的Andr​​oid?多个、适配器、数据库、oid

2023-09-11 20:14:13 作者:回眸ら醉倾城

我读了引用创建一个数据库适配器类来创建并访问一个数据库表中的Andr​​oid SQLite的记事本教程。当使用多表SQLite数据库打交道,是不是最好的做法,以创造一个不同的适配器类为每个表或整个Android应用程序创建一个单一的数据库适配器类?

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?

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

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.

下面是在DB适配器表中的一个的例​​子。其他适配器都遵循同样的格式具有不同的实现。

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

在第一个适配器,在这种情况下usersinfo,被访问时,一切都按预期工作。比方说,我有另一个适配器朋友的消息遵循相同的结构上面,当它是由不同的活动访问,这似乎对我来说,SQLiteOpenHelper的嵌套子将再次尝试创建数据库。显然,什么是错的,因为在那种情况下,我的应用程序崩溃。

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.

那么,在Android上的标准做法是建立一个单一的庞大数据库适配器,而不是每个表的单个适配器?

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

推荐答案

下面是解决方案,我终于结束了实施。它是一种混搭的方式积累了Commonsware书籍,网络周围的一些东西,我希望我书签,因为我想给信贷:

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.

在我的应用程序启动画面开始,我用的方法presented Android对于初学者:为Android 创建多个SQLite的表

When my app splash screen starts, I use the technique presented Android For Beginners: Creating multiple SQLite Tables for Android

所以,我的主要DBAdapter(负责创建所有的我的表在单个DB)看起来是这样的:

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

在DBAdapter类只被调用时,应用程序第一次启动其唯一的责任是创建/更新表。所有其他访问的数据通过个人适配器类来完成。我发现,这个完美的作品,并没有创造我前面提到的版本问题。

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.

希望这有助于。

 
精彩推荐
图片推荐