【问题标题】:Android: can I use one SQLiteOpenHelper class for multiple database files?Android:我可以对多个数据库文件使用一个 SQLiteOpenHelper 类吗?
【发布时间】:2010-11-20 17:31:35
【问题描述】:

我的应用程序使用两个数据库(单独的文件)。为了处理这些数据库,我创建了两个扩展 SQLiteOpenHelper 的 Helper 类,每个数据库一个。

我现在要添加第三个数据库,想知道是否需要创建另一个 Helper 类(如果我使用第 4 个和第 5 个数据库,我需要更多的 Helper 类),还是可以使用相同的 Helper多个数据库的类?

我在尝试仅使用一个 Helper 类时看到的问题是我看不到如何将各个数据库文件的名称传递给 Helper。目前,数据库的名称被硬编码为每个 Helper 类的静态字段,但如果我只有一个 Helper 类,我需要能够在创建单独的 Helper 时将不同的名称传递给构造函数物体;问题在于,Android 似乎只使用一个参数调用 SQLiteOpenHelper 构造函数:上下文。

【问题讨论】:

  • 嘿伙计!我正在做一些与你非常相似的事情,但就我而言,我需要 2 个不同的 dbHelper 类。事情是我在尝试这样做时遇到错误。 java.lang.IllegalStateException: Helper 类是 X 类,但正试图重置为 Y 类。你遇到过这个问题吗?

标签: android database sqlite class-design


【解决方案1】:

当然可以。这只是您的 Helper 类设计的问题。您可以将 DB 的名称传递给您的 Helper 类构造函数(以及所需的 Context 实例),而不是硬编码:

public class DBOpenHelper extends SQLiteOpenHelper {

    public DBOpenHelper(Context context, String dbName, int dbVersion) {
        super(context, dbName, null, dbVersion);
    }
...
}

【讨论】:

  • 傻我!我没有正确阅读我的 Helper 对象代码创建代码。正如你所说,这很简单。
  • 嗨,我想问一个问题(希望它不是太简单/太明显)你如何遍历帮助类来创建所有数据库?您是否使用 for 循环遍历助手类以获取要创建的数据库数量并传入所有数据库名称?
【解决方案2】:

您需要一个实现此处描述的升级过程的抽象类。然后为每个表扩展这个抽象类。在您的抽象类中,您必须以某种方式(列表,硬编码)存储您的表格,因此当 onUpgrade 触发您迭代表格项目并为每个表格项目执行描述的步骤时。他们将自我升级,保留所有现有的细节。请注意 onUpgrade 事件每个数据库只触发一次,这就是为什么您需要遍历所有表来升级所有表的原因。您在整个数据库中只维护 1 个版本号。

  • 开始交易
  • 使用if not exists 运行表创建(我们正在进行升级,因此该表可能尚不存在,它将失败更改并删除)
  • 将现有列List<String> columns = DBUtils.GetColumns(db, TableName); 放入列表中
  • 备份表 (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
  • 创建新表(最新的表创建模式)
  • 获取与新列的交集,这次是从升级表中获取的列 (columns.retainAll(DBUtils.GetColumns(db, TableName));)
  • 恢复数据 (String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName)); )
  • 删除备份表 (DROP table 'temp_" + TableName)
  • setTransactionSuccessful

(这不处理表降级,如果重命名列,由于列名不匹配,因此不会传输现有数据)。

.

public static List<String> GetColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("select * from " + tableName + " limit 1", null);
        if (c != null) {
            ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
        }
    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null)
            c.close();
    }
    return ar;
}

public static String join(List<String> list, String delim) {
    StringBuilder buf = new StringBuilder();
    int num = list.size();
    for (int i = 0; i < num; i++) {
        if (i != 0)
            buf.append(delim);
        buf.append((String) list.get(i));
    }
    return buf.toString();
}

【讨论】:

  • 恐怕这对我来说太复杂了!也许我应该坚持为多个数据库使用多个 Helper 类。
  • 那里有所有复杂的代码片段。您只需要包装一个 for 循环并将交易内容包装起来。还有比这更复杂的事情。
【解决方案3】:

使用附加到 ApplicationContext 的单个数据库访问对象来处理 SqliteAssetHelper 实现,使用 getInstance() 而不是对每个连接使用 DAO 构造函数,确保在应用程序生命周期中打开和关闭一次连接,您可以在应用程序生命周期中尽可能多地查询数据库,同时避免内存泄漏。

    /**
         * Private constructor to avoid object creation from outside classes.
         *
         */
        private Databa

seAccess() {

        this.masterOpenHelper = DatabaseOpenHelper.getInstance( "master.db");
        this.dictionaryOpenHelper = DatabaseOpenHelper.getInstance( "dictionary.db");
        isAlreadyOpen = false;
    }

    /**
     * Return a singleton instance of DatabaseAccess.
     *
     * @return the instance of DabaseAccess
     */
    public static DatabaseAccess getInstance() {


        if (instance == null) {
            instance = new DatabaseAccess();
            instance.open();
        }

        return instance;
    }

/**
 * Open the database connection.
 */
public void open() {

    this.masterDatabase = masterOpenHelper.getWritableDatabase();
    Log.i(TAG, "master db is opened " + masterDatabase.isOpen());

    this.dictionaryDatabase = dictionaryOpenHelper.getWritableDatabase();
    Log.i(TAG, "dictionary db is opened " + dictionaryDatabase.isOpen());

    isAlreadyOpen = true;
}

/**
 * Close the database connection.
 */
public void close() {

    if (masterDatabase != null) {
        this.masterDatabase.close();
        Log.i(TAG, "masterdb closed " + !this.masterDatabase.isOpen());
    }

    if(dictionaryDatabase != null) {
        this.dictionaryDatabase.close();
        Log.i(TAG, "dictionary closed " + !this.dictionaryDatabase.isOpen());
    }

    instance = null;
}

SqliteAssetHelper 对象

public class DatabaseOpenHelper extends SQLiteAssetHelper {
    private static final String TAG = "DatabaseOpenHelper";
    public static String DATABASE_NAME;
    private static final int DATABASE_VERSION = 1;
    private static DatabaseOpenHelper masterDb, dictionaryDb;

    private DatabaseOpenHelper(String name) {
        super(MyApp.mContext.get(), name, null, DATABASE_VERSION); // mContext is a WeakReference object
        DATABASE_NAME = name; 
    }

    public static synchronized DatabaseOpenHelper getInstance(String name) {

        switch (name){

            case "master.db":

                if(masterDb == null)
                    masterDb = new DatabaseOpenHelper(name);

                return  masterDb;

            case "dictionary.db":

                if(dictionaryDb == null)
                    dictionaryDb = new DatabaseOpenHelper(name);

                return dictionaryDb;

            default:
                Log.i(TAG, "database not found " + name);
                return null;
        }
    }

【讨论】:

    猜你喜欢
    • 2014-03-17
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2020-08-09
    • 2012-01-21
    • 1970-01-01
    • 2010-11-01
    • 2018-05-17
    相关资源
    最近更新 更多