program tip

Android의 여러 테이블 SQLite DB 어댑터?

radiobox 2020. 12. 5. 09:32
반응형

Android의 여러 테이블 SQLite DB 어댑터?


DB 테이블을 만들고 액세스하기 위해 DB 어댑터 클래스를 만드는 방법을 참조하는 Android SQLite NotePad 자습서를 읽고있었습니다. 다중 테이블 SQLite 데이터베이스를 다룰 때 각 테이블에 대해 다른 어댑터 클래스를 생성하거나 전체 Android 애플리케이션에 대해 단일 DB 어댑터 클래스를 생성하는 것이 모범 사례입니까?

내 응용 프로그램은 여러 테이블을 사용하며 단일 대규모 어댑터 클래스가 필요하지 않기를 바랐습니다. 그러나 문제는 각 어댑터 내의 메모장 예제에 따라 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의 중첩 된 하위 클래스가 데이터베이스를 다시 만들려고 시도하는 것처럼 보입니다. 이 시나리오에서 내 앱이 충돌하기 때문에 분명히 뭔가 잘못되었습니다.

그렇다면 Android 내에서 테이블 당 개별 어댑터 대신 하나의 거대한 db 어댑터를 만드는 것이 표준 관행입니까?


내가 결국 구현 한 솔루션은 다음과 같습니다. Commonsware 서적에서 얻은 정보와 내가 북마크하고 싶은 웹 관련 정보에서 일종의 매시업입니다.

db에서 가져와야하는 각 데이터 유형에 대해 "어댑터"클래스 (아무것도 하위 클래스가 아님)를 만듭니다. 이러한 어댑터 클래스는 해당 정보에 대한 db에 액세스하는 데 필요한 모든 메소드를 보유합니다. 예를 들어, DB에 세 개의 테이블이있는 경우 :

  1. 자동차
  2. 보트
  3. 오토바이

다음과 비슷한 세 개의 어댑터가있을 것입니다 (데모로 하나만 넣 겠지만 아이디어는 각각 동일합니다).

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

}

따라서 각 테이블에 대해 이러한 클래스 "어댑터"중 하나가 있다고 상상해보십시오.

내 앱 시작 화면이 시작되면 초보자를위한 Android : Android 용 여러 SQLite 테이블 만들기에 제시된 기술을 사용합니다 .

따라서 내 기본 DBAdapter (단일 DB에 모든 테이블을 생성하는 역할을 함)는 다음과 같습니다.

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 클래스는 앱이 처음 시작될 때만 호출되며 유일한 책임은 테이블을 생성 / 업그레이드하는 것입니다. 데이터에 대한 다른 모든 액세스는 개별 "어댑터"클래스를 통해 수행됩니다. 나는 이것이 완벽하게 작동하고 앞서 언급 한 버전 관리 문제를 일으키지 않는다는 것을 발견했습니다.

도움이 되었기를 바랍니다.


같은 문제가 있었고 많은 솔루션을 시도했지만 마침내 데이터베이스 구조를 구성하고 테이블 클래스에 대한 클래스를 확장하는 추상 메서드를 만들었습니다.

이것은 내 데이터베이스 생성자 클래스이며 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.

참고URL : https://stackoverflow.com/questions/4063510/multiple-table-sqlite-db-adapters-in-android

반응형