问题
Why does the coping of database not work for Android 9? My implementation is based on this example (video). Everything works fine on Android versions from 4.1 up to 10, but NOT on 9 Pie.
Here what I did:
fun importToApp(fileNameOnSD: String) {
val sd = File(sdFolder)
if (sd.canWrite()) {
val currentDB = File(Environment.getDataDirectory(), dataTemp)
val backupDB = File(sd, fileNameOnSD)
if (currentDB.exists()) {
try {
val src = FileInputStream(backupDB).channel
val dst = FileOutputStream(currentDB).channel
dst.transferFrom(src, 0, src.size())
src.close()
dst.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
copyData()
}
private fun copyData() {
db.delete(TABLE, null, null)
val dbBackup = context.openOrCreateDatabase(DB_TEMP, Context.MODE_PRIVATE, null)
val cursor = dbBackup.query(true, TABLE, null, null, null, null, null, null, null)
cursor.moveToFirst()
while (!cursor.isAfterLast) {
db.insert(TABLE, null, modelToValues(cursorToModel(cursor)))
cursor.moveToNext()
}
cursor.close()
context.deleteDatabase(dataTemp)
utilities.toast(context.resources.getString(R.string.db_suc_imported), 0)
}
I also call the method (as proposed here):
override fun onOpen(db: SQLiteDatabase) {
super.onOpen(db)
if (Build.VERSION.SDK_INT == 28)
db.disableWriteAheadLogging()
}
Here is the crash caused in Android Pie:
E/SQLiteLog: (1) no such table: Cars
D/AndroidRuntime: Shutting down VM
--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.easyapps.cryptnote, PID: 3174
android.database.sqlite.SQLiteException: no such table: Cars (code 1 SQLITE_ERROR): , while compiling: SELECT DISTINCT * FROM Cars
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1255)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1126)
at com.easyapps.cryptnote.ListDatabase.copyData(CarsDatabase.kt:144)
at com.easyapps.cryptnote.ListDatabase.importToApp(CarsDatabase.kt:137)
at com.easyapps.cryptnote.ImportActivity$importDB$$inlined$apply$lambda$1.onClick(CarsActivity.kt:273)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 3174 SIG: 9
This line val cursor = dbBackup.query(true, TABLE, null, null, null, null, null, null, null)
crashes the app. So far I tested in on two different real Android devices, one with Android Lollipop (Moto) and one with Android Pie (Samsung A40). The other versions were virtual. The most interesting thing is that it works on Samsung with Android Pie, but not on a virtual device with Android Pie. Nevertheless, I assume that is the Samsung device is exception, I need to get run on all Android devices, no matter real or virtual.
回答1:
So, I fixed the issue by using the first answer. I added an internal class
class TempDataBase(private val context: Context, dbName: String, version: Int) : SQLiteOpenHelper(
context,
dbName, null,
version
) {
override fun onCreate(db: SQLiteDatabase) {
db.execSQL("CREATE TABLE $TABLE ($ID INTEGER PRIMARY KEY AUTOINCREMENT, $TITLE TEXT, $NOTE TEXT, $DATE TEXT);")
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS $TABLE")
onCreate(db)
}
override fun onConfigure(db: SQLiteDatabase) {
db.disableWriteAheadLogging()
super.onConfigure(db)
}
}
and called it in my copyData()
method:
private fun copyData() {
db.delete(TABLE, null, null)
val dbBackup = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
SQLiteDatabase.openDatabase(TempDataBase(context, DB_TEMP, 1).readableDatabase.path, null, SQLiteDatabase.OPEN_READWRITE)
}
else
context.openOrCreateDatabase(DB_TEMP, Context.MODE_PRIVATE, null)
val cursor = dbBackup.query(true, TABLE,null,null,null,null,null,null, null)
cursor.moveToFirst()
while (!cursor.isAfterLast) {
db.insert(TABLE, null, modelToValues(cursorToModel(cursor)))
cursor.moveToNext()
}
cursor.close()
db.close()
context.deleteDatabase(dataTemp)
utilities.toast(context.resources.getString(R.string.db_suc_imported), 0)
}
Basically, Android P looks for a database and detects that is does not exist while other versions do not really require that a temp database must really exist. My inner class creates a temp database as buffer to copy data in used by Android 9.
Whoever still looking for a solution, please leave a comment for more info and I will respond asap.
来源:https://stackoverflow.com/questions/60608884/e-sqlitelog-1-no-such-table-cars-on-android-9-pie