重新創建意圖后,我在每個資料庫查詢中都會遇到例外。我認為這可能是因為重新創建活動的方式,但不知道如何解決這個問題。
我在更改語言和黑暗模式后重新創建它。
重新創建活動時拋出例外:
嘗試重新打開一個已經關閉的物件:SQLiteDatabase:
活動
private lateinit var db: SQLiteDatabase
private lateinit var oh: LOTDatabaseHelper
...
在創建
...
oh = LOTDatabaseHelper(this)
db = oh.readableDatabase
...
銷毀
...
db.close()
oh.close()
...
以及我如何重新創造意圖
val intent = intent
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
startActivity(intent)
finish()
編輯:
我發現 Activity 大約創建了兩次,然后留下一個,其余的被銷毀。OnDestroy 似乎適用于所有活動并關閉資料庫,這應該是不可能的。
現在我導航到啟影片面,然后導航到使用資料庫的活動,一切正常。那么當 Activity 被自己替換時,為什么生命周期不能很好地作業?
uj5u.com熱心網友回復:
在打開一個已經關閉的資料庫由不匹配的打開和關閉的常見原因。
通常修復方法是簡單地不打開和關閉資料庫(除非特別需要,例如從備份副本恢復資料庫,或強制 WAL 檢查點備份資料庫),而只是打開資料庫一次。
通常不需要繼續打開和關閉資料庫,因為當應用程式完成時,資料庫將關閉(您可以隨時關閉它,這是最重要的活動的 onDestroy)。此外,打開資料庫是一種資源成本很高的資源,因此多次打開是資源浪費/低效的。
- 也許看Android SQLite DB 何時關閉
我建議洗掉所有關閉。您可能還希望考慮單例方法,甚至可能在 Helper 中擁有所有資料庫功能。
作為一個例子,也許考慮:-
助手DBHelper :-
class LOTDatabaseHelper(context: Context): SQLiteOpenHelper(
context,
DATABASE_NAME,
null,
DATABASE_VERSION) {
companion object {
const val DATABASE_NAME = "my.db"
const val DATABASE_VERSION = 1
@Volatile
private var instance: SQLiteDatabase? = null
fun getInstance(context: Context): SQLiteDatabase {
if (instance == null) {
instance = LOTDatabaseHelper(context).writableDatabase
}
return instance as SQLiteDatabase
}
}
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(Table1.CREATE_SQL)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
TODO("Not yet implemented")
}
override fun onDowngrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
super.onDowngrade(db, oldVersion, newVersion)
}
fun insert(name: String): Long {
val cv = ContentValues()
cv.put(Table1.COL_NAME,name)
return instance!!.insert(Table1.TABLE_NAME,null,cv)
}
fun getAllFromTable1() : Cursor {
return instance!!.query(Table1.TABLE_NAME,null,null,null,null,null,"${Table1.COL_NAME} ASC")
}
@SuppressLint("Range")
fun logAll() {
val csr = getAllFromTable1()
var row = 1
val nameix = csr.getColumnIndex(COL_NAME)
while (csr.moveToNext()) {
Log.d("CURSORINFO","Row ${row } ${COL_NAME} is ${csr.getString(csr.getColumnIndex(
COL_NAME))}")
//val test = csr.getString(csr.getColumnIndex("${COL_NAME}"))
}
csr.close()
}
// Table stuff
class Table1 {
companion object {
const val TABLE_NAME = "table1"
const val COL_ID = BaseColumns._ID
const val COL_NAME = "${TABLE_NAME}_name"
const val CREATE_SQL = "CREATE TABLE IF NOT EXISTS $TABLE_NAME (${COL_ID} INTEGER PRIMARY KEY, $COL_NAME TEXT);"
}
}
}
用于呼叫第二個活動MainActivity的初始活動:-
class MainActivity : AppCompatActivity() {
val TAG = "MAINACTIVITYINFO"
private lateinit var dbother: DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
dbother = DBHelper.getInstance(this)!!
dbother.insert("TESTOTHER") // Use the Insert in the DBHelper
/* of course you can still get an SQLiteDatabase */
/* There is very little use getting readable as it gets writable */
/* so get writable is more accurate description */
var sqliteDatabase = dbother.writableDatabase //<<<<<< can be used
logCursorInfo(dbother.allAsCursor)
// NOW Start the other Activity
Log.d(TAG,"starting Activity2")
intent = Intent(this,Activity2::class.java)
startActivity(intent)
Log.d(TAG,"after starting Activity2")
}
override fun onDestroy() {
super.onDestroy()
Log.d("ONDESTROY","On Destroy invoked.")
}
override fun onResume() {
super.onResume()
Log.d(TAG,"On Resume invoked")
dbother = DBHelper.getInstance(this)!!
}
//
@SuppressLint("Range")
fun logCursorInfo(csr: Cursor) {
val nameix = csr.getColumnIndex(LOTDatabaseHelper.Table1.COL_NAME)
val idix = csr.getColumnIndex(LOTDatabaseHelper.Table1.COL_ID)
while (csr.moveToNext()) {
//Log.d(TAG,"${LOTDatabaseHelper.Table1.COL_ID} = ${csr.getString(idix)} ${LOTDatabaseHelper.Table1.COL_NAME} = ${csr.getString(nameix)}")
Log.d(TAG,"${csr.getString(csr.getColumnIndex(LOTDatabaseHelper.Table1.COL_NAME))}")
}
}
companion object {
var counter: Int = 0
}
}
- 這使用 DBHelper 但獲取一個實體,然后添加幾行,提取它們然后啟動第二個活動。
Activity2 the activity where you are having the issues :-
class Activity2 : AppCompatActivity() {
val TAG = "ACTIVITY2INFO"
private lateinit var dbother: DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_2)
Log.d(TAG,"Activity 2 Started (onCreate). $this")
dbother = DBHelper.getInstance(this)!! // Get the Database
dbother.insert("TESTOTHER_ACTIVITY2") // Add a row
var csr = dbother.allAsCursor // get All the rows
DatabaseUtils.dumpCursor(csr) // dump the cursor
csr.close() // close the cursor
/* Start another activity (will loop so stop with counter)*/
Log.d(TAG,"Restarting Activity. counter is ${counter } $this")
if (counter < 3) {
val intent = intent
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
startActivity(intent) //<<<<<<<<<< RUN 1 Not the Way as starts a new activity
/* Perhaps the following???? */
// this.intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
//this.recreate() //<<<<<<<<<< RUN 2 perhaps the way but no intent
}
Log.d(TAG,"Finishing Activity 2 $this")
finish()
}
companion object {
var counter: Int = 0
}
override fun onResume() {
super.onResume()
Log.d(TAG,"OnResume Invoked. $this")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG,"OnDestory (after super call - before db close and helper close. $this)")
Log.d(TAG,"OnDestory (after all. $this)")
}
}
- This gets an (the) DBHelper instance, inserts a row, extracts all the data and then starts another activity NOTING that this would loop endlessly so hence the counter.
Hopefully the comments will be of assistance.
As you can see I've included quite a bit of logging. However, as suggested the database is never closed.
Running the App
Here's the results of running the App i.e. the log (from a fresh install) :-
2021-10-06 19:52:50.715 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
2021-10-06 19:52:50.717 D/MAINACTIVITYINFO: TESTOTHER
2021-10-06 19:52:50.717 D/MAINACTIVITYINFO: starting Activity2
2021-10-06 19:52:50.724 D/MAINACTIVITYINFO: after starting Activity2
2021-10-06 19:52:50.734 D/MAINACTIVITYINFO: On Resume invoked
2021-10-06 19:52:50.734 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
2021-10-06 19:52:50.848 D/ACTIVITY2INFO: Activity 2 Started (onCreate). a.a.so69454766kotlinsqlite.Activity2@3269902
2021-10-06 19:52:50.848 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
2021-10-06 19:52:50.850 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@950aa67
2021-10-06 19:52:50.851 I/System.out: 0 {
2021-10-06 19:52:50.852 I/System.out: _id=1
2021-10-06 19:52:50.852 I/System.out: table1_name=TESTOTHER
2021-10-06 19:52:50.852 I/System.out: }
2021-10-06 19:52:50.852 I/System.out: 1 {
2021-10-06 19:52:50.852 I/System.out: _id=2
2021-10-06 19:52:50.852 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:50.852 I/System.out: }
2021-10-06 19:52:50.852 I/System.out: <<<<<
2021-10-06 19:52:50.856 D/ACTIVITY2INFO: Restarting Activity. counter is 0 a.a.so69454766kotlinsqlite.Activity2@3269902
2021-10-06 19:52:50.864 D/ACTIVITY2INFO: Finishing Activity 2 a.a.so69454766kotlinsqlite.Activity2@3269902
2021-10-06 19:52:51.020 D/ACTIVITY2INFO: Activity 2 Started (onCreate). a.a.so69454766kotlinsqlite.Activity2@7db7a75
2021-10-06 19:52:51.020 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
2021-10-06 19:52:51.021 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@7fc80ae
2021-10-06 19:52:51.021 I/System.out: 0 {
2021-10-06 19:52:51.021 I/System.out: _id=1
2021-10-06 19:52:51.021 I/System.out: table1_name=TESTOTHER
2021-10-06 19:52:51.021 I/System.out: }
2021-10-06 19:52:51.021 I/System.out: 1 {
2021-10-06 19:52:51.021 I/System.out: _id=2
2021-10-06 19:52:51.022 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:51.022 I/System.out: }
2021-10-06 19:52:51.022 I/System.out: 2 {
2021-10-06 19:52:51.022 I/System.out: _id=3
2021-10-06 19:52:51.022 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:51.022 I/System.out: }
2021-10-06 19:52:51.022 I/System.out: <<<<<
2021-10-06 19:52:51.023 D/ACTIVITY2INFO: Restarting Activity. counter is 1 a.a.so69454766kotlinsqlite.Activity2@7db7a75
2021-10-06 19:52:51.030 D/ACTIVITY2INFO: Finishing Activity 2 a.a.so69454766kotlinsqlite.Activity2@7db7a75
2021-10-06 19:52:51.081 D/ACTIVITY2INFO: Activity 2 Started (onCreate). a.a.so69454766kotlinsqlite.Activity2@3433874
2021-10-06 19:52:51.081 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
2021-10-06 19:52:51.082 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@5c713d1
2021-10-06 19:52:51.082 I/System.out: 0 {
2021-10-06 19:52:51.082 I/System.out: _id=1
2021-10-06 19:52:51.082 I/System.out: table1_name=TESTOTHER
2021-10-06 19:52:51.082 I/System.out: }
2021-10-06 19:52:51.082 I/System.out: 1 {
2021-10-06 19:52:51.083 I/System.out: _id=2
2021-10-06 19:52:51.083 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:51.083 I/System.out: }
2021-10-06 19:52:51.083 I/System.out: 2 {
2021-10-06 19:52:51.083 I/System.out: _id=3
2021-10-06 19:52:51.083 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:51.083 I/System.out: }
2021-10-06 19:52:51.083 I/System.out: 3 {
2021-10-06 19:52:51.083 I/System.out: _id=4
2021-10-06 19:52:51.083 I/System.out: table1_name=TESTOTHER_ACTIVITY2
2021-10-06 19:52:51.083 I/System.out: }
2021-10-06 19:52:51.083 I/System.out: <<<<<
2021-10-06 19:52:51.084 D/ACTIVITY2INFO: Restarting Activity. counter is 2 a.a.so69454766kotlinsqlite.Activity2@3433874
2021-10-06 19:52:51.084 D/ACTIVITY2INFO: Finishing Activity 2 a.a.so69454766kotlinsqlite.Activity2@3433874
2021-10-06 19:52:51.097 D/MAINACTIVITYINFO: On Resume invoked
2021-10-06 19:52:51.097 D/DBHELPERINFO: getInstance returning instance a.a.so69454766kotlinsqlite.DBHelper@59860ab
One thing of note is the the DBHelper instance that is retrieved is always DBHelper@59860ab (i.e. the single instance).
As you have noted what happens with the Activity is that another is is started. You may wish to try using the commented out:-
/* Perhaps the following???? */
// this.intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
//this.recreate() //<<<<<<<<<< RUN 2 perhaps the way but no intent
- I'm not sure whether this would achieve what you desire though.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/311423.html
