gpt4 book ai didi

android - 使用预先填充的数据库运送 android 应用程序

转载 作者:行者123 更新时间:2023-12-03 17:01:22 25 4
gpt4 key购买 nike

这是我的代码,

public DBHelper(Context context) {
super(context, DB_NAME, null, 2);
this.context = context;
DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath();
}

@Override
public void onCreate(SQLiteDatabase db) {
createDataBase();
}

private void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
copyDataBase();
}
}

private boolean checkDataBase() {
System.out.println("DB_PATH : " + DB_PATH);
File dbFile = new File(DB_PATH);
return dbFile.exists();
}

private void copyDataBase() {
Log.i("Database",
"New database is being copied to device!");
byte[] buffer = new byte[1024];
OutputStream myOutput;
int length;
InputStream myInput;
try {
myInput = context.getAssets().open(DB_NAME);
myOutput = new FileOutputStream(DB_PATH);
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database",
"New database has been copied to device!");
} catch (IOException e) {
e.printStackTrace();
}
}

一切正常,我什至收到日志 New database has been copyed to device!,但是当我尝试从 db 读取数据时,我得到 no such table异常。

注意:我正在尝试更新我的一个旧应用程序,同样的代码在旧设备版本(如 5.0 及更低版本)中有效,但当我尝试使用最新设备更新应用程序时,它不起作用。

最佳答案

假设您已复制到 Assets 文件夹的数据库确实包含表,那么我相信您的问题是您正在实例化 DBHelper 的实例,然后您通过隐式或显式方式隐式打开了数据库调用 getWritableDatabase 或 getReadableDatabase,然后使用 onCreate 方法启动复制。

如果是这样,那么 get?????ableDatabase 将创建一个空数据库,副本会覆盖它,但在更高版本的 Android 9+ 上,-shm 和 -wal 文件将保持原样,然后数据库将被删除打开,然后由于 -shm 和 -wal 文件与原始空数据库不匹配,检测到损坏,因此创建了一个空的新数据库,因为 SDK 代码试图提供可用的数据库。

有 3 个修复。

  • 使用 disableWriteAheadLogging通过重写 SQLiteOpenHelper 类的 onConfigure 方法来实现。然后使用旧的日志模式。

  • 确保未调用 getWritableDatabase/getReadableDatabase。这可以通过确保在实例化 DBHelper 实例时完成复制来完成。

  • 确保删除 -wal 和 -shm 文件(如果它们在复制时存在)。

使用第一个可能只会延迟不可避免的事情,并不真正推荐,因为它没有利用 WAL 模式的好处。

您的 DBHelper 的以下版本包含第二个修复程序,并且作为预防措施还包含第三个修复程序:-

public class DBHelper extends SQLiteOpenHelper {

public static final String DB_NAME = "myDBName";
public static String DB_PATH;

Context context;

public DBHelper(Context context) {
super(context, DB_NAME, null, 2);
this.context = context;
//<<<<<<<<<< ADDED (moved from createDatabase) 1st Fix >>>>>>>>>>
DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath();
if (!checkDataBase()) {
copyDataBase();
}
//<<<<<<<<<< END OF ADDED CODE >>>>>>>>>>
this.getWritableDatabase(); //<<<<<<<<<< Added to force an open after the copy - not essential
}

@Override
public void onCreate(SQLiteDatabase db) {
//createDataBase(); <<<<<<<<<< relying on this was the cause of the issue >>>>>>>>>>
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

//<<<<<<<<<< NOT NEEDED AND SHOULD NOT BE CALLED >>>>>>>>>
private void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
copyDataBase();
}
}

private boolean checkDataBase() {
System.out.println("DB_PATH : " + DB_PATH);
File dbFile = new File(DB_PATH);
if (dbFile.exists()) return true;
//<<<<<<<<<< ADDED to create the databases directory if it doesn't exist >>>>>>>>>>
//it may be that getWritableDatabase was used to circumvent the issue that the copy would fail in the databases directory does not exist, hence this fix is included
if (!new File(dbFile.getParent()).exists()) {
new File(dbFile.getParent()).mkdirs();
}
return false;
}

private void copyDataBase() {
Log.i("Database",
"New database is being copied to device!");
byte[] buffer = new byte[1024];
//<<<<<<<<<< ADDED to delete wal and shm files if they exist (3rd fix) >>>>>>>>>>
File dbDirectory = new File(new File(DB_PATH).getParent());
File dbwal = new File(dbDirectory.getPath() + File.separator + DB_NAME + "-wal");
if (dbwal.exists()) {
dbwal.delete();
}
File dbshm = new File(dbDirectory.getPath() + File.separator + DB_NAME + "-shm");
if (dbshm.exists()) {
dbshm.delete();
}
//<<<<<<<<<< END OF ADDED CODE >>>>>>>>>>

OutputStream myOutput;
int length;
InputStream myInput;
try {
myInput = context.getAssets().open(DB_NAME);
myOutput = new FileOutputStream(DB_PATH);
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database",
"New database has been copied to device!");
} catch (IOException e) {
e.printStackTrace();
}
}
}

这已经在 Android 5 和 Android 10 上使用以下 Activity 代码进行了测试(以及用于转储架构的附加代码(请注意,显然不是您的数据库,而是可用的数据库)):-

DBHelper mDBHlpr;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);

根据日志的结果:-

2019-05-07 06:20:53.148 I/System.out: DB_PATH : /data/user/0/soa.usingyourownsqlitedatabaseblog/databases/myDBName
2019-05-07 06:20:53.148 I/Database: New database is being copied to device!
2019-05-07 06:20:53.149 I/Database: New database has been copied to device!
2019-05-07 06:20:53.168 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@e3fe34f
2019-05-07 06:20:53.169 I/System.out: 0 {
2019-05-07 06:20:53.169 I/System.out: type=table
2019-05-07 06:20:53.169 I/System.out: name=Categories
2019-05-07 06:20:53.169 I/System.out: tbl_name=Categories
2019-05-07 06:20:53.169 I/System.out: rootpage=2
2019-05-07 06:20:53.169 I/System.out: sql=CREATE TABLE "Categories" (
2019-05-07 06:20:53.169 I/System.out: "not_id" integer NOT NULL,
2019-05-07 06:20:53.169 I/System.out: "CategoryLabel" TEXT,
2019-05-07 06:20:53.169 I/System.out: "Colour" integer,
2019-05-07 06:20:53.169 I/System.out: PRIMARY KEY ("not_id")
2019-05-07 06:20:53.169 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.170 I/System.out: 1 {
2019-05-07 06:20:53.170 I/System.out: type=table
2019-05-07 06:20:53.170 I/System.out: name=Content
2019-05-07 06:20:53.170 I/System.out: tbl_name=Content
2019-05-07 06:20:53.170 I/System.out: rootpage=3
2019-05-07 06:20:53.170 I/System.out: sql=CREATE TABLE "Content" (
2019-05-07 06:20:53.170 I/System.out: "again_not_id" INTEGER NOT NULL,
2019-05-07 06:20:53.170 I/System.out: "Text" TEXT,
2019-05-07 06:20:53.170 I/System.out: "Source" VARCHAR,
2019-05-07 06:20:53.170 I/System.out: "Category" integer,
2019-05-07 06:20:53.170 I/System.out: "VerseOrder" integer,
2019-05-07 06:20:53.170 I/System.out: PRIMARY KEY ("again_not_id")
2019-05-07 06:20:53.170 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: 2 {
2019-05-07 06:20:53.171 I/System.out: type=table
2019-05-07 06:20:53.171 I/System.out: name=android_metadata
2019-05-07 06:20:53.171 I/System.out: tbl_name=android_metadata
2019-05-07 06:20:53.171 I/System.out: rootpage=4
2019-05-07 06:20:53.171 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-05-07 06:20:53.171 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: <<<<<

关于android - 使用预先填充的数据库运送 android 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56008907/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com