来自Assets文件夹的SQLite数据库在Android Pie即API中不起作用28

时间:2018-11-28 11:01:53

标签: android database sqlite android-9.0-pie

我已在我的资产文件夹中添加了sqlite文件,并在我的应用程序中使用了sqlite文件中的数据。直到API 27(例如,牛轧糖)都可以正常工作。但是该应用程序因Android Pie即API 28而崩溃。我通过以下方式在数据库帮助程序类中使用以下方法。请帮帮我。

    public Database(Context context, String databaseName) {
             super(context, databaseName, null, DATABASE_VERSION);
             this.context = context;
             String packageName = context.getPackageName();
             DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
             DB_NAME = databaseName;
             openDataBase();
           }

         public void createDataBase() {
             boolean dbExist = checkDataBase();
             if (!dbExist) {
               this.getReadableDatabase();
               try {
                 copyDataBase();
               } catch (IOException e) {
                 Log.e(this.getClass().toString(), "Copying error");
                 throw new Error("Error copying database!");
               }
             }else{
               SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
               int dbVersion = prefs.getInt(SP_KEY_DB_VER, 1);
               if (DATABASE_VERSION != dbVersion) {
                 File dbFile = context.getDatabasePath(DB_NAME);
                 if (dbFile.delete()) {
                   database.deleteDatabase(new File(DB_PATH + DB_NAME));
                   openDataBase();
                 }
               }
             }
           }

 private boolean checkDataBase() {
     SQLiteDatabase checkDb = null;
     try {
       String path = DB_PATH + DB_NAME;
       //checkDb = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
       checkDb = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
     } catch (SQLException e) {
       Log.d(TAG, "Error while checking db");
     }
     if (checkDb != null) {
       checkDb.close();
     }
     return checkDb != null;
   }

   private void copyDataBase() throws IOException {
     InputStream externalDbStream = context.getAssets().open(DB_NAME);

     String outFileName = DB_PATH + DB_NAME;

     OutputStream localDbStream = new FileOutputStream(outFileName);

     byte[] buffer = new byte[1024];
     int bytesRead;
     while ((bytesRead = externalDbStream.read(buffer)) > 0) {
       localDbStream.write(buffer, 0, bytesRead);
     }
     SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
     SharedPreferences.Editor editor = prefs.edit();
     editor.putInt(SP_KEY_DB_VER, DATABASE_VERSION);
     editor.commit();
     localDbStream.close();
     externalDbStream.close();
   }


    public SQLiteDatabase openDataBase() throws SQLException {

         String path = DB_PATH + DB_NAME;
         if (database == null) {
         createDataBase();
         database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);
       }
      return database;
     }

这些是我正在使用的openDatabase,copyDatabase和创建数据库方法。

这是崩溃日志-

  

android.database.sqlite.SQLiteException:没有这样的表:quran_chapters   (代码1 SQLITE_ERROR):,而在编译时:SELECT * FROM   古兰经           在android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native   方法)           在android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)           在android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)           在android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)           在android.database.sqlite.SQLiteProgram。(SQLiteProgram.java:58)           在android.database.sqlite.SQLiteQuery。(SQLiteQuery.java:37)           在android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)           在android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)           在android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)

1 个答案:

答案 0 :(得分:2)

如果数据库不存在,则使用 this.getReadableDatabase(); 创建数据库,并且由于您可能在onCreate方法中没有执行任何操作,因此数据库为空。

>

然后,用副本覆盖磁盘,但是由于数据库仍处于打开状态(通过this.getReadableDatabase();),因此空的,无表的数据库可能会完全保留在缓存中,因此会出现问题。

使用一种在数据库不存在时打开数据库的方法似乎是在解决该问题,即当它是第一个数据库且该应用程序的存储没有名为数据库的目录(打开它会创建目录)。

  • 注意,在大多数情况下,getReadableDatabase将获得可写的数据库。

我个人更喜欢并且没有遇到任何问题,方法是:-

  1. 从不对数据库路径进行硬编码,而总是使用Context的 getDatabasePath 方法。例如:-  mDBPath = context.getDatabasePath(database).getPath();
  2. 检查数据库文件是否存在以查看数据库是否存在,而不是打开数据库以查看其是否存在。 (请参见示例3)

  3. 检查数据库的父级(即,databases文件夹)是否存在,以及是否不使用File的 mkdirs 方法创建数据库目录。例如:-

    private boolean ifDatabaseExists(String dbpath) { File db = new File(dbpath); if(db.exists()) return true; File dir = new File(db.getParent()); if (!dir.exists()) { dir.mkdirs(); } return false; }

  4. 将数据库从资产复制到1处获得的路径所指定的位置。

    • 作为4的一部分,我获得了资产文件,请检查前16个字节以查看其是否为有效的SQLiteDatabase(必须为“ SQLite格式3 \ u0000”)。

    • ,然后继续将数据库从资产复制到数据库文件。