应用关闭时如何删除Room数据库?Activity中调用ViewModel删除报错如何解决?
问题根因
两个异常现象的核心原因均为Room数据库操作未在后台线程执行:
- onDestroy中调用未生效:onDestroy属于Activity生命周期末尾回调,系统内存紧张时会直接销毁Activity而不触发该回调;同时主线程执行的数据库操作还未完成时,进程就可能被系统回收,导致逻辑未执行。
- onStop中调用报错:Room默认禁止主线程执行IO操作,避免长时间阻塞UI引发ANR,直接调用会抛出主线程访问数据库的异常。
解决方案(协程实现,生产环境推荐)
通过Kotlin协程将数据库操作切换到后台线程执行,各层代码修改如下:
1. 修改DAO层接口
给删除方法添加suspend关键字,限定该方法只能在协程环境中调用:
@Dao interface NoteDAO { @Query("select * from note_table") fun getAllNote() : LiveData<List<Note>> @Query("DELETE FROM note_table") suspend fun deleteAllData() }
2. 修改Repository层方法
对应删除方法也声明为挂起函数:
class NoteRepository(app:Application) { private val noteDAO : NoteDAO init { val noteDatabase: NoteDatabase = NoteDatabase.getInstance(app) noteDAO = noteDatabase.getNoteDao() } fun getAllNote():LiveData<List<Note>> = noteDAO.getAllNote() suspend fun deleteAllData() = noteDAO.deleteAllData() }
3. 修改ViewModel层逻辑
使用viewModelScope启动协程执行删除操作,ViewModel销毁时协程会自动取消,避免内存泄漏:
class NoteViewModel(app: Application): ViewModel() { private val noteRepository: NoteRepository = NoteRepository(app) fun deleteAllData() = viewModelScope.launch { noteRepository.deleteAllData() } fun getAllNote() : LiveData<List<Note>> = noteRepository.getAllNote() class NoteViewModelFactory(private val application: Application) : ViewModelProvider.Factory{ override fun <T : ViewModel?> create(modelClass: Class<T>): T { if(modelClass.isAssignableFrom(NoteViewModel::class.java)){ return NoteViewModel(application) as T } throw IllegalArgumentException("Unable construct viewmodel") } } }
如果项目中找不到viewModelScope,需要在Module级build.gradle中添加依赖:
dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" // 可替换为最新稳定版 }
4. 原调用代码无需修改
onStop中的原有调用逻辑可直接使用,修改后不会再抛出主线程访问异常。
补充说明
- 调用时机优化:onDestroy执行可靠性极低,如果需求是用户退出页面即清空数据,建议将调用逻辑放在
onBackPressed()等用户主动触发退出的回调中,执行时机更可控。 - 不推荐临时方案:如果仅做测试,可在RoomDatabase初始化时调用
allowMainThreadQueries()方法允许主线程操作数据库,但该方案会带来UI卡顿、ANR风险,禁止在生产环境使用。
内容的提问来源于stack exchange,提问作者Lộc Trần Phước
相关产品推荐
相关产品推荐

