Android 使用它直到下次需要复制/重写数据库时为止

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

这个答案帮助我弄明白:

在我的AndStatus应用程序中,Android 9出现了这个问题,该应用程序有相当大的一套自动测试,在提交之前,在Android 9 emulator中始终复制“SQLiteException:没有这样的表”:
所以,如果您真的很好奇,您可以在提交之前和之后运行所有测试,以查看差异。

最简单的答案是在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(提前写入日志)。需要执行以下两个步骤

  • 通过在参考资料下的values文件夹的config.xml中的以下行禁用该选项
  • 假的

  • 在createDatabase方法中的DBAdapter类中进行以下更改。否则,早期Android版本的手机会崩溃

    私有void createDataBase()引发IOException{

    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();