我已在我的资产文件夹中添加了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)
答案 0 :(得分:2)
如果数据库不存在,则使用 this.getReadableDatabase(); 创建数据库,并且由于您可能在onCreate方法中没有执行任何操作,因此数据库为空。
>然后,用副本覆盖磁盘,但是由于数据库仍处于打开状态(通过this.getReadableDatabase();
),因此空的,无表的数据库可能会完全保留在缓存中,因此会出现问题。
使用一种在数据库不存在时打开数据库的方法似乎是在解决该问题,即当它是第一个数据库且该应用程序的存储没有名为数据库的目录(打开它会创建目录)。
我个人更喜欢并且没有遇到任何问题,方法是:-
mDBPath = context.getDatabasePath(database).getPath();
检查数据库文件是否存在以查看数据库是否存在,而不是打开数据库以查看其是否存在。 (请参见示例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;
}
将数据库从资产复制到1处获得的路径所指定的位置。
作为4的一部分,我获得了资产文件,请检查前16个字节以查看其是否为有效的SQLiteDatabase(必须为“ SQLite格式3 \ u0000”)。
,然后继续将数据库从资产复制到数据库文件。