3

Android アプリに既存のものを含める必要がありSQLiteDatabase、新しいデータベースをダウンロードしてインストールする機能も必要です。私はいくつかの調査を行い、私の最初の実用的な解決策はhere から来ました。私はその解決策が好きではありませんでした.1つには、データベースが常に固定パスにあり、その他の奇妙な点があることを前提としています.

そこで、既存のデータベース ファイルをアセットに入れるのではなく、データベースを SQL ファイルにエクスポートして読み込み、onCreate()my のメソッドで、ファイル データを使用して openでSQLiteOpenHelper新しいメソッドを呼び出し ます。解決したと思ういくつかの問題に遭遇しましたが、すべての問題について考えていなかったと確信しています。updateDatabaseDataInputStream

  1. SQLiteOpenHelperのメソッドが呼び出されるとonCreate、データベースが作成され、開かれinTransaction()true. その結果、インポートされた sql ファイルに が含まれBEGIN TRANSACTIONている場合は例外がスローされ、sql 文字列にステートメントが含まれている場合は'android_metadata'さらに別の例外が作成されます。そこで、String.contains()これらのキーワードを検索する単純な検索を追加し、それらを実行しないように を設定boolean doExecute しました。false質問は、これをフィルタリングするためのより良い SQL クラスまたはメソッド、あるいはより良い正規表現メソッドはありますか?

  2. SQL ファイルに予期しない改行があるという同様の問題。とでファイルを読み、readLine()改行を探します。単純String.trim()にその行で使用し、endsWith(";"). これにより、1 行に複数のステートメントがないなど、入力ファイルにいくつかの制約が課されます。では、ファイルから SQL を前処理するより良い方法はありますか?

リソースまたはダウンロードから取得した後にデータベースを作成するために使用するコードは次のとおりDataInputStreamです。assets

    public boolean updateDatabase(DataInputStream inStream, SQLiteDatabase db, boolean doClear) throws Error {
    String sqlStatement = null;
    boolean result = true;
    boolean inOnCreate = true;
    boolean wasInTransaction;

    if(doClear) dropDatabase();

    // if called from onCreate() db is open and inTransaction, else getWritableDatabase()
    if(db == null) {
        inOnCreate = false;
        db = this.getWritableDatabase();
    }

    wasInTransaction = db.inTransaction();  // see NB below

    boolean doExecute;
    try {
        while ((sqlStatement = inStream.readLine()) != null) {
            // trim, so we can look for ';'
            sqlStatement.trim();
            if(!sqlStatement.endsWith(";")) {
                continue;   // line breaks in file, get whole statement
            }

            // NB - my file (exported from SQLite Database Browser starts with "BEGIN TRANSACTION;". 
            // executing this throws SQLiteException: cannot start a transaction within a transaction
            // According to SQLiteDatabase doc for beginTransaction(), "Transactions can be nested"
            // so this is a problem
            // but... possibly it is an "exclusive transaction" ?
            doExecute = true;
            if(wasInTransaction) {
                // don't execute BEGIN TRANSACTION; or COMMIT;
                if((sqlStatement.contains("BEGIN" ) || sqlStatement.contains("begin" )) &&
                        (sqlStatement. contains("TRANSACTION") || sqlStatement.contains("transaction" ))) {
                    doExecute = false;
                }
                if(sqlStatement.contains("COMMIT") || sqlStatement.contains("commit")) {
                    doExecute = false;
                }
            }   // inTransaction
            // this statement could be in older databases, but this scheme doesn't need, can't have it
            if(sqlStatement.contains("android_metadata")) {
                doExecute = false;
            }
            if(doExecute) {
                try {
                    db.execSQL(sqlStatement);
                } catch (SQLException e) {
                    throw(new Error("Error executing SQL " + sqlStatement));
                }   // try/catch
            }   // doExecute
        }   // while()
    } catch (IOException e) {
        result = false; // which won't matter if we throw 
        throw(new Error("Error reading  " + DB_SQL));
    } 

    if(!inOnCreate) {
        db.close();
    }

    return result;
}
4

1 に答える 1

1

このような野心的で洗練された実装を早期に実行する必要はありませんが、データベースを既に作成し、データベース ブラウザーなどでチェックしている場合は、SQLite Asset Helper を検討したことがありますか? 主な問題がアセット フォルダーの使用を余儀なくされていた場合、この方法libを使用すると、指定した任意のディレクトリからファイルを使用できます。さらに、生.dbファイルの処理も可能です。チェックアウトする価値があります。

于 2012-11-18T00:57:38.100 に答える