如果您的应用程序需要一个数据库,并且它带有内置数据,那么交付该应用程序的最佳方式是什么?我应该:

预创建SQLite数据库,并将其包含在。apk? 在应用程序中包含SQL命令,并让它在第一次使用时创建数据库并插入数据?

我所看到的缺点是:

可能的SQLite版本不匹配可能会导致问题,我目前不知道数据库应该去哪里以及如何访问它。 在设备上创建和填充数据库可能需要很长时间。

有什么建议吗?关于任何问题的文档指针将非常感激。


当前回答

将数据库导入apk,然后复制到/data/data/…将使数据库的大小增加一倍(1在apk, 1在data/data/…),并将增加apk的大小(当然)。所以你的数据库不应该太大。

其他回答

从我所看到的,你应该是一个已经有表设置和数据的数据库。然而,如果你愿意(取决于你拥有的应用程序类型),你可以允许“升级数据库选项”。然后你要做的就是下载最新的sqlite版本,获得在线托管的文本文件的最新Insert/Create语句,执行这些语句,并从旧的db进行数据传输到新的db。

目前还没有办法预先创建一个SQLite数据库来与apk一起发布。最好的方法是将适当的SQL保存为资源,并从应用程序中运行它们。是的,这会导致数据的重复(同样的信息作为资源和数据库存在),但目前没有其他方法。唯一的缓解因素是apk文件被压缩了。我的经验是908KB压缩到268KB以下。

下面的帖子有我找到的最好的讨论/解决方案,其中有很好的示例代码。

http://groups.google.com/group/android-developers/msg/9f455ae93a1cf152

我把我的CREATE语句存储为一个字符串资源,用Context.getString()读取,并用SQLiteDatabse.execSQL()运行。

我将插入的数据存储在res/raw/inserts中。sql(我创建了sql文件,7000+行)。使用上面链接的技术,我输入了一个循环,逐行读取文件,并将数据连接到“INSERT INTO tbl VALUE”,并执行另一个sqlitedatbase . execsql()。当它们可以连接时,保存7000个“INSERT INTO tbl VALUE”是没有意义的。

在模拟器上大约需要20秒,我不知道在真正的手机上需要多长时间,但它只发生一次,当用户第一次启动应用程序时。

我的解决方案既不使用任何第三方库,也不强迫您在SQLiteOpenHelper子类上调用自定义方法来在创建时初始化数据库。它还负责数据库升级。所有需要做的就是子类化SQLiteOpenHelper。

先决条件:

你希望与应用一起发布的数据库。它应该包含一个名为android_metadata的1x1表,其属性locale值为en_US,此外还有应用特有的表。

子类化SQLiteOpenHelper:

子类SQLiteOpenHelper。 在SQLiteOpenHelper子类中创建一个私有方法。此方法包含将数据库内容从“assets”文件夹中的数据库文件复制到在应用程序包上下文中创建的数据库的逻辑。 重写SQLiteOpenHelper的onCreate, onUpgrade和onOpen方法。

足够的说。下面是SQLiteOpenHelper子类:

public class PlanDetailsSQLiteOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = "SQLiteOpenHelper";

    private final Context context;
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "my_custom_db";

    private boolean createDb = false, upgradeDb = false;

    public PlanDetailsSQLiteOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }

    /**
     * Copy packaged database from assets folder to the database created in the
     * application package context.
     * 
     * @param db
     *            The target database in the application package context.
     */
    private void copyDatabaseFromAssets(SQLiteDatabase db) {
        Log.i(TAG, "copyDatabase");
        InputStream myInput = null;
        OutputStream myOutput = null;
        try {
            // Open db packaged as asset as the input stream
            myInput = context.getAssets().open("path/to/shipped/db/file");

            // Open the db in the application package context:
            myOutput = new FileOutputStream(db.getPath());

            // Transfer db file contents:
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
            }
            myOutput.flush();

            // Set the version of the copied database to the current
            // version:
            SQLiteDatabase copiedDb = context.openOrCreateDatabase(
                DATABASE_NAME, 0, null);
            copiedDb.execSQL("PRAGMA user_version = " + DATABASE_VERSION);
            copiedDb.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new Error(TAG + " Error copying database");
        } finally {
            // Close the streams
            try {
                if (myOutput != null) {
                    myOutput.close();
                }
                if (myInput != null) {
                    myInput.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new Error(TAG + " Error closing streams");
            }
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(TAG, "onCreate db");
        createDb = true;
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG, "onUpgrade db");
        upgradeDb = true;
    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        Log.i(TAG, "onOpen db");
        if (createDb) {// The db in the application package
            // context is being created.
            // So copy the contents from the db
            // file packaged in the assets
            // folder:
            createDb = false;
            copyDatabaseFromAssets(db);

        }
        if (upgradeDb) {// The db in the application package
            // context is being upgraded from a lower to a higher version.
            upgradeDb = false;
            // Your db upgrade logic here:
        }
    }
}

最后,要获得一个数据库连接,只需在SQLiteOpenHelper子类上调用getReadableDatabase()或getWritableDatabase(),它将负责创建一个db,如果数据库不存在,则从'assets'文件夹中的指定文件复制db内容。

简而言之,您可以使用SQLiteOpenHelper子类来访问资产文件夹中附带的db,就像您在onCreate()方法中使用SQL查询初始化数据库一样。

将数据库导入apk,然后复制到/data/data/…将使数据库的大小增加一倍(1在apk, 1在data/data/…),并将增加apk的大小(当然)。所以你的数据库不应该太大。

我写了一个库来简化这个过程。

dataBase = new DataBase.Builder(context, "myDb").
//        setAssetsPath(). // default "databases"
//        setDatabaseErrorHandler().
//        setCursorFactory().
//        setUpgradeCallback()
//        setVersion(). // default 1
build();

它将从assets/databases/myDb.db文件创建一个dataBase。 此外,你会得到所有这些功能:

从文件加载数据库 同步访问数据库 使用SQLite - Android通过requery, Android特定分发最新版本的SQLite。

从github克隆。