And*_*cha 7 android android-room
您好,我有2个应用程序仅通过将数据库文件复制到sdcard中和从中复制数据库文件来依赖于制作和恢复数据库的备份,并且在弄清楚如何在关闭数据库以使其成为数据库后如何重新打开Room Database单例方面遇到了困难份。
建立数据库:
@Database(version = 15, exportSchema = true, entities = [list of entities])
abstract class AppDatabase : RoomDatabase() {
//list of DAOs
companion object {
@Volatile private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also {
INSTANCE = it
}
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"Fazendao.sqlitedb"
)
.addMigrations(Migration1315)
.build()
}
}
Run Code Online (Sandbox Code Playgroud)
关闭数据库:
fun closeDatabase() {
if(db.isOpen) {
db.openHelper.close()
}
}
Run Code Online (Sandbox Code Playgroud)
复制数据库文件(在ViewModel内部):
fun exportaBkpObservable(nome: String, auto: String, storage: File, database: File) {
disposable.clear()
setFlagsNull()
flagSubject.onNext(false)
disposable.add(
Observable.fromCallable {
repo.recordBkpName(nome)
}
.subscribeOn(Schedulers.io())
.flatMap {
return@flatMap try {
//closing the database
repo.closeDatabase()
Observable.just(
database.copyTo(File(storage, auto), true)
)
.flatMap {
val myDb = SQLiteDatabase.openOrCreateDatabase(it, null)
val ok = myDb.isDatabaseIntegrityOk
if(myDb.isOpen) myDb.close()
if(ok) {
Observable.just(ok)
} else {
Observable.error<Throwable>(Throwable("CORRUPTED DATABASE"))
}
}
} catch (t: Throwable) {
Observable.error<Throwable>(t)
}
}
.subscribe(
{},
{
errorFlag = "exportDB: " + it.message
errorSubject.onNext("exportDB: " + it.message)
},
{
//trying to reopen database
repo.openDatabase()
trueFlag = true
flagSubject.onNext(true)
}
)
)
}
Run Code Online (Sandbox Code Playgroud)
存储库是将AppDatabase注入的存储库,而该存储库又被注入到ViewModelFactory中。
注射:
object MainInjection {
private fun providesIORepo(context: Context): IORepo {
return IORepo(AppDatabase.getInstance(context))
}
fun provideIOViewModelFactory(context: Context): IOViewModelFactory {
val data = providesIORepo(context)
return IOViewModelFactory(data)
}
}
Run Code Online (Sandbox Code Playgroud)
并在AppCompatActivity onCreate中:
val modelFactory = MainInjection.provideIOViewModelFactory(this)
viewModel = ViewModelProviders.of(this, modelFactory).get(IOViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
重新打开数据库:
fun openDatabase() {
if(!db.isOpen){
db.openHelper.writableDatabase
}
}
Run Code Online (Sandbox Code Playgroud)
现在出现错误信息:
尝试重新打开数据库:
E/ROOM: Invalidation tracker is initialized twice :/.
Run Code Online (Sandbox Code Playgroud)
因此,当我尝试从另一个函数访问它时发生崩溃:
Cannot perform this operation because the connection pool has been closed.
Run Code Online (Sandbox Code Playgroud)
有时在关闭数据库后,我也会:
E/ROOM: Cannot run invalidation tracker. Is the db closed?
Run Code Online (Sandbox Code Playgroud)
在这篇文章中,从SQLite逐步迁移到Room,作者为每次访问打开和关闭数据库,因此我不理解为什么我的实现无法正常工作。
那我在哪里错了?有没有办法停用InvalidationTracker?
每当我必须复制数据库文件时,是否应该使用以下代码关闭数据库并清除Room实例。安全吗?
fun destroyInstance() {
if (INSTANCE?.isOpen == true) {
INSTANCE?.close()
}
INSTANCE = null
}
Run Code Online (Sandbox Code Playgroud)
感谢您的关注。
好的,我开始使用以下代码关闭数据库:
fun destroyInstance() {
if (INSTANCE?.isOpen == true) {
INSTANCE?.close()
}
INSTANCE = null
}
Run Code Online (Sandbox Code Playgroud)
并实现导入数据库如下
fun importaBkpObservable(origin: File, database: File) {
disposable.clear()
setFlagsNull()
flagSubject.onNext(false)
disposable.add(
Observable.fromCallable {
try {
repo.closeDatabase()
val myDb = SQLiteDatabase.openOrCreateDatabase(origin, null)
val ok = myDb.isDatabaseIntegrityOk
if (myDb.isOpen) myDb.close()
if(ok) {
origin.copyTo(database, true)
} else {
"CORRUPTED DATABASE"
}
} catch (t: Throwable) {
t.message
}
}
.subscribeOn(Schedulers.io())
.subscribe(
{
if(it != null) {
if(it is String) {
errorFlag = "exportDB: $it"
errorSubject.onNext("exportDB: $it")
} else {
trueFlag = true
flagSubject.onNext(true)
}
} else {
errorFlag = "exportDB: GENERIC"
errorSubject.onNext("exportDB: GENERIC")
}
},
{
errorFlag = "exportDB: ${it.message}"
errorSubject.onNext("exportDB: ${it.message}")
}
)
)
}
Run Code Online (Sandbox Code Playgroud)
我曾经通过startActivityForResult()从我的主要活动导航到导入/导出活动,但现在已更改为startActivity()在此调用之后完成我的主要活动。导入/导出完成后,我使用startActivity()调用了我的主要活动,然后完成了导入/导出活动。
这样,我的主要活动ViewModel就会用新的AppDatabase实例再次实例化,并且一切正常。
我调查了Android Profiler,几次导入和导出后的内存使用量在90 MB到130 MB之间,与之前我没有关闭数据库时的情况相同,所以我认为我没有遇到某种内存泄漏的情况或累积Room Database实例。
我还应该检查什么?
归档时间: |
|
查看次数: |
4543 次 |
最近记录: |