错误:无法访问主线程上的数据库,因为它可能会长时间锁定 UI。- 使用 Kotlin 的 Android Room

Kle*_*kus 5 mobile android kotlin android-room android-jetpack

好的,所以,我正在尝试使用 Android Room 为这个项目创建这个数据库。

首先,这是我在 Gradle 文件中关于这个问题的内容:

//Room database
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.1.0"

    implementation "androidx.room:room-runtime:2.2.3"
    kapt "androidx.room:room-compiler:2.2.3"
    implementation "androidx.room:room-ktx:2.2.3"
Run Code Online (Sandbox Code Playgroud)

这是道代码:

@Dao
interface DebtsDao {

    @Query("SELECT * FROM debts")
    fun getDebtsList() : List<Debts>

    @Query("SELECT * FROM debts WHERE name LIKE :name")
    fun getNamedDebt(name : String) : Debts

    @Insert
    fun insertInDatabase(debt : Debts)

    @Delete
    fun deleteFromDatabase(debt : Debts)

}
Run Code Online (Sandbox Code Playgroud)

数据库位:

@Database(entities = arrayOf(Debts::class), version = 1)
abstract class AppDatabase : RoomDatabase()
{
    abstract fun debtsDao() : DebtsDao
}

Run Code Online (Sandbox Code Playgroud)

这是我使用它的功能:

    fun refreshRecyclerView()
    {
        val database = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "account").build()

        val list : List<Debts> = database.debtsDao().getDebtsList()

        recycler_view_debts.layoutManager = LinearLayoutManager(this)
        recycler_view_debts.adapter = RecAdapter(this, list)
    }
Run Code Online (Sandbox Code Playgroud)

我尝试按照 Android 页面上的教程进行操作,但没有按预期工作。我在 Android Studio 上收到以下错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.project.watchingmoneyfly, PID: 17067
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.project.watchingmoneyfly/com.project.watchingmoneyfly.Activities.MainActivity}: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
     Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:267)
        at androidx.room.RoomDatabase.beginTransaction(RoomDatabase.java:351)
        at com.project.watchingmoneyfly.RoomDatabase.DebtsDao_Impl.insertInDatabase(DebtsDao_Impl.java:79)
        at com.project.watchingmoneyfly.Activities.MainActivity.onCreate(MainActivity.kt:25)
        at android.app.Activity.performCreate(Activity.java:6662)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6077) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 
Run Code Online (Sandbox Code Playgroud)

这应该是问题的根源:无法访问主线程上的数据库,因为它可能会长时间锁定 UI。

我在这里缺少什么?提前致谢!!

Vir*_*hit 10

房间数据库不希望用户在主线程上执行操作。

\n\n

您应该使用后台线程来执行任务。

\n\n

您可以使用

\n\n
.allowMainThreadQueries()\n
Run Code Online (Sandbox Code Playgroud)\n\n

跳过建议的解决方案,但建议使用线程来执行任务。

\n\n

以下是一些选项。

\n\n

1)

\n\n

AsyncTask.execute(() -> //Write your db code here);

\n\n

2)

\n\n
 Thread {\n       //Do your database\xc2\xb4s operations here\n       }.start()\n
Run Code Online (Sandbox Code Playgroud)\n


zsm*_*b13 7

Room 阻止您从 UI 线程使用它,因为数据库查询将访问磁盘,这可能需要很长时间,并且在此期间阻塞 UI 线程将冻结用户界面。你应该从后台线程调用 Room,你如何到达那里取决于你。您可以选择 Java 线程原语、Executors、RxJava、协程等,具体取决于您熟悉的内容。

从技术上讲,您可以通过使用 来规避 Room 的这种限制allowMainThreadQueries,但出于上述原因,您永远不应在实际应用程序中这样做。此开关仅用于测试。

您还可以查看到返回LiveDataFlowable或相似类型这是从本质室异步,因为在这些情况下,你可以调用从UI线程间的方法。

有关更多信息,请参阅Room 文档