如果您的应用程序需要一个数据库,并且它带有内置数据,那么交付该应用程序的最佳方式是什么?我应该:
预创建SQLite数据库,并将其包含在。apk? 在应用程序中包含SQL命令,并让它在第一次使用时创建数据库并插入数据?
我所看到的缺点是:
可能的SQLite版本不匹配可能会导致问题,我目前不知道数据库应该去哪里以及如何访问它。 在设备上创建和填充数据库可能需要很长时间。
有什么建议吗?关于任何问题的文档指针将非常感激。
如果您的应用程序需要一个数据库,并且它带有内置数据,那么交付该应用程序的最佳方式是什么?我应该:
预创建SQLite数据库,并将其包含在。apk? 在应用程序中包含SQL命令,并让它在第一次使用时创建数据库并插入数据?
我所看到的缺点是:
可能的SQLite版本不匹配可能会导致问题,我目前不知道数据库应该去哪里以及如何访问它。 在设备上创建和填充数据库可能需要很长时间。
有什么建议吗?关于任何问题的文档指针将非常感激。
当前回答
2017年11月,谷歌发布了房间持久性库。
从文档中可以看到:
Room持久库在SQLite上提供了一个抽象层 允许流畅的数据库访问,同时利用 SQLite。 该库可以帮助您在设备上创建应用程序数据的缓存 这个缓存,作为你的应用程序的单一 真实源,允许用户查看一致的密钥副本 应用程序中的信息,不管用户是否有 互联网连接。
当第一次创建或打开数据库时,Room数据库具有回调。可以使用create回调填充数据库。
Room.databaseBuilder(context.applicationContext,
DataDatabase::class.java, "Sample.db")
// prepopulate the database after onCreate was called
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// moving to a new thread
ioThread {
getInstance(context).dataDao()
.insert(PREPOPULATE_DATA)
}
}
})
.build()
这篇博文中的代码。
其他回答
我写了一个库来简化这个过程。
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克隆。
目前还没有办法预先创建一个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秒,我不知道在真正的手机上需要多长时间,但它只发生一次,当用户第一次启动应用程序时。
在Android Studio 3.0中附带数据库文件发布应用程序
对我来说,发布带有数据库文件的应用程序是个好主意。这样做的优点是不需要进行复杂的初始化,如果数据集很大,初始化有时会花费大量时间。
步骤1:准备数据库文件
准备好数据库文件。它可以是.db文件或.sqlite文件。如果您使用.sqlite文件,您所需要做的就是更改文件扩展名。步骤是一样的。
在本例中,我准备了一个名为testDB.db的文件。它有一个表和一些样本数据,像这样
步骤2:将文件导入到项目中
如果您还没有资产文件夹,请创建资产文件夹。然后将数据库文件复制并粘贴到此文件夹中
步骤3:复制文件到应用程序的数据文件夹
你需要将数据库文件复制到应用程序的数据文件夹中,以便与它进行进一步的交互。这是复制数据库文件的一次性操作(初始化)。如果多次调用此代码,data文件夹中的数据库文件将被assets文件夹中的数据库文件覆盖。当你想在未来的应用程序更新期间更新数据库时,这个覆盖过程是有用的。
注意,在应用程序更新期间,这个数据库文件不会在应用程序的数据文件夹中被更改。只有卸载才会删除它。
数据库文件需要复制到“/databases”文件夹下。打开设备文件资源管理器。输入data/data/<YourAppName>/ location。这是上面提到的应用程序的默认数据文件夹。默认情况下,数据库文件将放在该目录下的另一个名为databases的文件夹中
现在,复制文件的过程与Java所做的非常相似。使用下面的代码进行复制粘贴。这是起始代码。它还可以用于将来更新(通过覆盖)数据库文件。
//get context by calling "this" in activity or getActivity() in fragment
//call this if API level is lower than 17 String appDataPath = "/data/data/" + context.getPackageName() + "/databases/"
String appDataPath = context.getApplicationInfo().dataDir;
File dbFolder = new File(appDataPath + "/databases");//Make sure the /databases folder exists
dbFolder.mkdir();//This can be called multiple times.
File dbFilePath = new File(appDataPath + "/databases/testDB.db");
try {
InputStream inputStream = context.getAssets().open("testDB.db");
OutputStream outputStream = new FileOutputStream(dbFilePath);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer))>0)
{
outputStream.write(buffer, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (IOException e){
//handle
}
然后刷新文件夹以验证复制过程
步骤4:创建数据库打开帮助程序
为SQLiteOpenHelper创建一个子类,包括连接、关闭、路径等。我把它命名为DatabaseOpenHelper
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "testDB.db";
public static final String DB_SUB_PATH = "/databases/" + DB_NAME;
private static String APP_DATA_PATH = "";
private SQLiteDatabase dataBase;
private final Context context;
public DatabaseOpenHelper(Context context){
super(context, DB_NAME, null, 1);
APP_DATA_PATH = context.getApplicationInfo().dataDir;
this.context = context;
}
public boolean openDataBase() throws SQLException{
String mPath = APP_DATA_PATH + DB_SUB_PATH;
//Note that this method assumes that the db file is already copied in place
dataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.OPEN_READWRITE);
return dataBase != null;
}
@Override
public synchronized void close(){
if(dataBase != null) {dataBase.close();}
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
步骤5:创建与数据库交互的顶级类
这将是读取和写入数据库文件的类。还有一个示例查询,用于打印数据库中的值。
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class Database {
private final Context context;
private SQLiteDatabase database;
private DatabaseOpenHelper dbHelper;
public Database(Context context){
this.context = context;
dbHelper = new DatabaseOpenHelper(context);
}
public Database open() throws SQLException
{
dbHelper.openDataBase();
dbHelper.close();
database = dbHelper.getReadableDatabase();
return this;
}
public void close()
{
dbHelper.close();
}
public void test(){
try{
String query ="SELECT value FROM test1";
Cursor cursor = database.rawQuery(query, null);
if (cursor.moveToFirst()){
do{
String value = cursor.getString(0);
Log.d("db", value);
}while (cursor.moveToNext());
}
cursor.close();
} catch (SQLException e) {
//handle
}
}
}
步骤6:测试运行
通过运行以下代码行来测试代码。
Database db = new Database(context);
db.open();
db.test();
db.close();
按下跑步键,欢呼吧!
如果所需的数据不是很大(限制我不知道,将取决于很多东西),你也可以从网站/网络应用下载数据(XML, JSON,无论什么)。接收到数据后,使用接收到的数据执行SQL语句,创建表并插入数据。
如果你的移动应用程序包含大量数据,稍后用更准确的数据或更改更新已安装的应用程序中的数据可能会更容易。
将数据库导入apk,然后复制到/data/data/…将使数据库的大小增加一倍(1在apk, 1在data/data/…),并将增加apk的大小(当然)。所以你的数据库不应该太大。