“无法访问主线程上的数据库,因为它可能会长时间锁定 UI。”我的协程错误
Posted
技术标签:
【中文标题】“无法访问主线程上的数据库,因为它可能会长时间锁定 UI。”我的协程错误【英文标题】:"Cannot access database on the main thread since it may potentially lock the UI for a long period of time." error on my Coroutine 【发布时间】:2019-12-30 15:14:47 【问题描述】:我的协程在我的协程上下文中指定的主线程上运行:
class ClickPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs), CoroutineScope, View.OnClickListener
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main
override fun onClick(v: View?)
when (key)
"logout" ->
CoroutineScope(coroutineContext).launch
CustomApplication.database?.clearAllTables()
Log.d("MapFragment", "Cleared Tables")
if (Profile.getCurrentProfile() != null) LoginManager.getInstance().logOut()
FirebaseAuth.getInstance().signOut()
val intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
但我仍然收到此错误:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
在我上面的协程调用CustomApplication.database?.clearAllTables()
到我的Room
数据库。
这是我的CustomApplication
:
class CustomApplication : Application()
companion object
var database: AppDatabase? = null
override fun onCreate()
super.onCreate()
CustomApplication.database = Room.databaseBuilder(this, AppDatabase::class.java, "AppDatabase").build()
如果我的协程上下文在主线程上运行,为什么我仍然会收到错误消息?
【问题讨论】:
看到这个***.com/questions/44167111/… 【参考方案1】:错误表明它不应该在主线程上运行。数据库操作(以及所有其他形式的 IO)可能需要很长时间,并且应该在后台运行。
您应该使用为运行 IO 操作而设计的Dispatchers.IO
。
【讨论】:
谢谢。诸如@Query("SELECT COUNT(*) FROM matched_users WHERE :matchId = match_id LIMIT 1")
之类的查询操作会如何使用Dispatchers.IO
?它不是输入/输出,因为它只是查询数据库。
您进行的任何数据库调用都应该从 IO 线程而不是主线程调用,从用户的角度来看,这对于 android 来说是非常宝贵的。
现在可以将 DAO 函数标记为挂起函数。那么你就不需要使用 Dispatchers.IO 来调用它了。与必须在协程的顶层包装阻塞调用相比,这是一种更简洁的解决方案。【参考方案2】:
您不能将Dispatchers.Main
用于长时间运行的任务。您必须使用Dispatchers.IO
进行数据库操作,如下所示:
class ClickPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs), CoroutineScope, View.OnClickListener
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO
override fun onClick(v: View?)
when (key)
"logout" ->
CoroutineScope(coroutineContext).launch
CustomApplication.database?.clearAllTables()
Log.d("MapFragment", "Cleared Tables")
if (Profile.getCurrentProfile() != null) LoginManager.getInstance().logOut()
FirebaseAuth.getInstance().signOut()
val intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
【讨论】:
谢谢。 @Query("SELECT COUNT(*) FROM matching_users WHERE :matchId = match_id LIMIT 1") 之类的查询操作会使用 Dispatchers.IO 吗?它不是输入/输出,因为它只是查询数据库。 数据库查询基本上是像文件读取一样从DB文件中读取,所以显然应该是IO操作。【参考方案3】:您好,这个问题是因为数据库必须在主线程上运行。 因此,您必须将这行代码添加到数据库中 部分
Room.databaseBuilder(context.getApplicationContext(),
DataBaseTextChat.class, Constants.DB_TEXT_CHAT)
.allowMainThreadQueries()
.addCallback(roomCallBack).build();
【讨论】:
这不是一个正确的解决方案!做负责任有思想的程序员,不要用!以上是关于“无法访问主线程上的数据库,因为它可能会长时间锁定 UI。”我的协程错误的主要内容,如果未能解决你的问题,请参考以下文章