Android 使用它直到下次需要复制/重写数据库时为止
这个答案帮助我弄明白: 在我的AndStatus应用程序中,Android 9出现了这个问题,该应用程序有相当大的一套自动测试,在提交之前,在Android 9 emulator中始终复制“SQLiteException:没有这样的表”:Android 使用它直到下次需要复制/重写数据库时为止,android,sqlite,android-9.0-pie,Android,Sqlite,Android 9.0 Pie,这个答案帮助我弄明白: 在我的AndStatus应用程序中,Android 9出现了这个问题,该应用程序有相当大的一套自动测试,在提交之前,在Android 9 emulator中始终复制“SQLiteException:没有这样的表”: 所以,如果您真的很好奇,您可以在提交之前和之后运行所有测试,以查看差异。最简单的答案是在Android PIE和更高版本中使用以下行作为数据库文件路径: DB_NAME="xyz.db"; DB_Path = "/data/data/" + BuildConf
所以,如果您真的很好奇,您可以在提交之前和之后运行所有测试,以查看差异。最简单的答案是在Android PIE和更高版本中使用以下行作为数据库文件路径:
DB_NAME="xyz.db";
DB_Path = "/data/data/" + BuildConfig.APPLICATION_ID + "/databases/"+DB_NAME;
以下是解决此问题的最佳方案: 只需在
SQLiteOpenHelper
类中重写此方法:
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
db.disableWriteAheadLogging();
}
}
我不能对接受的答案发表评论,因此我必须打开一个新的答案 mContext.getDatabasePath()不打开数据库连接,它甚至不需要现有文件名即可成功(请参阅sources/android-28/android/app/ContextImpl.java):
@覆盖
公共文件getDatabasePath(字符串名称){
文件目录;
文件f;
if(name.charAt(0)=File.separatorChar){
//剪断
}否则{
dir=getDatabasesDir();
f=makeFilename(dir,name);
}
返回f;
}
私有文件makeFilename(文件基,字符串名){
if(name.indexOf(File.separatorChar)<0){
返回新文件(基、名称);
}
抛出新的IllegalArgumentException(
“文件”+name+“包含路径分隔符”);
}
在版本p中,主要更改是WAL(提前写入日志)。需要执行以下两个步骤
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
this.getWritableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(android.os.Build.VERSION.SDK\u INT
}我有同样的东西,我有一个android版本4的应用程序,当更新我的手机有android 9时,我花了2天的时间试图找到错误,感谢我的评论,我只需要添加这个。close()
准备运行所有版本 Android Pie中出现的问题, 解决办法是:
SQLiteDatabase db = this.getReadableDatabase();
if (db != null && db.isOpen())
db.close();
copyDataBase();
你能检查你的输入流是否为空吗?使用Android调试器?我可以确认输入流不为空。紧接着
返回true
添加Log.d(“COPYINFO”,“Bytes Copied=“+String.valueOf(totalcount)+”到“+filepath”)代码>日志的结果输出是什么?运行Android 8.1的我的设备上的输出是(D/COPYINFO:Bytes Copied=1687552 to/data/user/0/am.radio/databases/s.db)Android P上的输出是(D/COPYINFO:Bytes Copied=1687552 to/data/user/0/am.radio/databases/s.db)它们完全相同。我的下一步,很明显,数据库正在被复制,因此需要检查数据库中的表。无论是查询sqlite_主表还是我个人都会在这里使用logDatabaseInfo方法[是否有任何方法可以帮助解决常见的sqlite问题?]()。不幸的是,关闭FileOutputStream
没有任何效果。同时切换到“使用资源尝试”方法会导致相同的空数据库。感谢您的持续帮助。我将代码替换为您的代码以获取文件路径,但同样的结果仍然存在。将创建一个空数据库,但不使用资产文件夹中的数据库填充该数据库。我应该补充说,我正在使用运行Android P的仿真器进行测试,而不是实际的设备,这不应该阻止代码按预期工作,是吗?我可以在仿真器上重现问题,这不是问题。也许你应该确保instant run已关闭,只是为了确保。无论如何,当我在从资产复制文件之前确保没有打开的数据库连接时,问题就解决了。这是关键。抱歉,你是对的。我忽略了我以前调用过这段(相当无意义的)代码:openOrCreateDatabase(Utils.getDatabaseName(),MODE_PRIVATE,null)代码>这保持了与数据库的打开连接,并导致了问题。我已经删除了该代码,一切正常。谢谢你的帮助!美好的很高兴你找到了答案。正如Ramon在下面指出的那样,禁用写前日志记录对我很有效。如何添加android_元数据表?您在回答中没有告诉我,我是使用SQLite数据库浏览器添加的。你可以用这个程序手动添加表格。嘿,我现在也面临同样的问题。我无法理解它如何恢复文件的副本,但缺少一个表,这怎么可能呢?关于如何在生产中解决这个问题,有什么线索吗?答案很好,但要挑剔的是,onConfigure
是一个更好的地方。onConfigure
的javadoc特别提到它是启用writeaheadloging
之类的地方。在我的测试中,这两个地方都致力于解决Android 9上的问题。从我这里开始!在我的例子中,如果“问题”只出现在9个Android版本上:如果(Build.version.SDK_INT>=28){database.disablewriteaheadloging();}我也遇到了同样的问题,它在版本9以下的设备上运行良好,现在你的解决方案在Pie上运行良好,谢谢。我在Android9上出错了。感谢您为我所做的工作,但如果我们禁用WAL,则会将写入量减少10%至15%,因为我面临着确切的问题,解决方案也起了作用,但我对这个问题感到好奇,为什么&如何在Android P中解决这个问题?谢谢!我花了3天时间寻找解决方案,但为什么?我想如何生成data-wal.db文件?emulator可以生成它吗?因为问题出现在真实设备上,而不是模拟器上。这是一个grea
class MySQLiteOpenHelper extends SQLiteOpenHelper {
MySQLiteOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, 2);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
private void copyDatabase(File dbFile, String db_name) throws IOException{
InputStream is = null;
OutputStream os = null;
SQLiteDatabase db = context.openOrCreateDatabase(db_name, Context.MODE_PRIVATE, null);
db.close();
try {
is = context.getAssets().open(db_name);
os = new FileOutputStream(dbFile);
byte[] buffer = new byte[1024];
while (is.read(buffer) > 0) {
os.write(buffer);
}
} catch (IOException e) {
e.printStackTrace();
throw(e);
} finally {
try {
if (os != null) os.close();
if (is != null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
db.disableWriteAheadLogging();
}
private void createDataBase() throws IOException {
this.getReadableDatabase();
this.close();
try {
copyDataBase();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
DB_NAME="xyz.db";
DB_Path = "/data/data/" + BuildConfig.APPLICATION_ID + "/databases/"+DB_NAME;
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
db.disableWriteAheadLogging();
}
}
@Override
public File getDatabasePath(String name) {
File dir;
File f;
if (name.charAt(0) == File.separatorChar) {
// snip
} else {
dir = getDatabasesDir();
f = makeFilename(dir, name);
}
return f;
}
private File makeFilename(File base, String name) {
if (name.indexOf(File.separatorChar) < 0) {
return new File(base, name);
}
throw new IllegalArgumentException(
"File " + name + " contains a path separator");
}
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) {
this.getWritableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void createDataBase () throws IOException {
this.getReadableDatabase ();
this.close ();
try {
copyDataBase ();
} catch (IOException e) {
throw new RuntimeException (e);
}
}
SQLiteDatabase db = this.getReadableDatabase();
if (db != null && db.isOpen())
db.close();
copyDataBase();