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에 세 개의 테이블이있는 경우 :
- 자동차
- 보트
- 오토바이
다음과 비슷한 세 개의 어댑터가있을 것입니다 (데모로 하나만 넣 겠지만 아이디어는 각각 동일합니다).
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
'program tip' 카테고리의 다른 글
HTML의 텍스트 상자에서 글꼴 크기를 변경하는 방법 (0) | 2020.12.05 |
---|---|
Entity Framework : db가 변경 될 때 모델을 어떻게 새로 고치나요? (0) | 2020.12.05 |
CPAN 모듈을 로컬 디렉토리에 어떻게 설치할 수 있습니까? (0) | 2020.12.04 |
OpenSSL 및 C ++로 sha256 생성 (0) | 2020.12.04 |
클래스 이름에 점 (.)으로 요소 스타일 지정 (0) | 2020.12.04 |