这是我的代码,
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 copied to device!
,但是当我尝试从db读取数据时,却遇到no such table
异常。
注意:我正在尝试更新我的一个旧应用程序,相同的代码可在5.0和更低版本的旧设备中使用,但是当我尝试使用最新设备更新该应用程序时,则不起作用。
答案 0 :(得分:2)
假设您已复制到资产文件夹的数据库确实包含该表,那么我认为您的问题是您正在实例化DBHelper的实例,然后隐式或显式地隐式打开了数据库。调用getWritableDatabase或getReadableDatabase,然后使用 onCreate 方法初始化副本。
如果是这样,则get?ableDatabase将创建一个空数据库,副本将覆盖此数据库,但是在更高版本的Android 9+上,-shm和-wal文件将保留原样,并且在数据库建立时保留打开,然后由于-shm和-wal文件与原始的空数据库不匹配,因此检测到损坏,因此当SDK代码尝试提供可用的数据库时,创建的新数据库为空。
有3个修复程序。
通过覆盖SQLiteOpenHelper类的onConfigure方法来使用disableWriteAheadLogging方法。然后,它将使用较旧的日记模式。
确保未调用getWritableDatabase / getReadableDatabase。这可以通过确保在实例化DBHelper实例时完成复制来完成。
确保-wal和-shm文件(如果在复制时存在)被删除。
使用第一种方法可能只会延迟不可避免的情况,因此不建议这样做,因为它没有利用WAL模式的好处。
以下版本的DBHelper包含第二个修订,并且作为预防措施还包含了第三个修订:-
how_many <- function(p){
gb <- ggplot_build(p)
length(gb$layout$panel_params[[1]][['x.major']])
}
raxe <- function(p, n){
gb <- ggplot_build(p)
x_params <- gb$layout$panel_params[[1]]
ni <- length(x_params[['x.major']])
labels <- x_params[['x.labels']]
if(ni < n){
dummy <- c(labels, paste0("__",letters[seq_len(n-ni)]))
print(dummy)
phantom <- c(labels, rep('', n-ni))
return(p + scale_x_discrete(lim=dummy, labels=phantom))
}
p
}
n_breaks <- sapply(p_list, how_many)
p_list <- lapply(p_list, raxe, max(n_breaks))
egg::ggarrange(plots = p_list, ncol=2)
这已在Android 5和Android 10上使用活动中的以下代码进行了测试(以及用于转储架构的其他代码(请注意,不是您的数据库而是可用的数据库)):-
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 + "-wal");
if (dbwal.exists()) {
dbwal.delete();
}
File dbshm = new File(dbDirectory.getPath() + File.separator + "=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();
}
}
}
根据日志的结果:-
DBHelper mDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);