【问题标题】:Kotlin Room Database - How to perform Sum Query on column?Kotlin Room Database - 如何对列执行求和查询?
【发布时间】:2021-04-04 00:11:47
【问题描述】:

我是 Kotlin 和 Android 编程的新手。我需要一些关于我的代码的帮助。我正在尝试对我的房间数据库中的列执行 SUM 查询,到目前为止它给我带来了麻烦。我试图让值返回为 Double 并且应用程序每次都会崩溃。 其中,expenseAmount 列是一个 Double 类型的列。

这是我目前所拥有的:

道:

@Dao
interface ExpenseDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun addExpense(expense: Expense)

    @Query("SELECT * FROM ExpenseListTable ORDER BY id ASC")
    fun readAllExpenseData(): LiveData<List<Expense>>

    @Delete
    suspend fun deleteExpense(expense: Expense)

    @Query("SELECT SUM(expenseAmount) FROM ExpenseListTable")
    fun getTotalExpense():Double

}

存储库:

class ExpenseRepository(private val expenseDao: ExpenseDao) {

    val readAllData:LiveData<List<Expense>> = expenseDao.readAllExpenseData()

    
    suspend fun addExpense(expense: Expense){
        expenseDao.addExpense(expense)
    }

    
    suspend fun deleteExpense(expense: Expense){
        expenseDao.deleteExpense(expense)
    }

    fun getTotal(): Double {
        return expenseDao.getTotalExpense()
    }
}

查看模型:

class ExpenseViewModel(application: Application): AndroidViewModel(application) {
   
    val readAllExpenseData: LiveData<List<Expense>>
 
    private val repository: ExpenseRepository
    
    init {
      
        val expenseDao = ExpenseDatabase.getDatabase(application).ExpenseDao()
      
        repository = ExpenseRepository(expenseDao)
      
        readAllExpenseData = repository.readAllData

    }
    fun addExpense(expense: Expense){
        viewModelScope.launch(Dispatchers.IO) {
            repository.addExpense(expense)
        }
    }

    
    fun deleteExpense(expense: Expense){
        viewModelScope.launch(Dispatchers.IO) {
        repository.deleteExpense(expense)}
    }
  
    fun getTotalExpense():Double{
        return repository.getTotal()
    }
}

活动.kt

 val sum = mExpenseViewModel.getTotalExpense()

这是错误:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.momoney101/com.android.momoney101.ExpenseList}: 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:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     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.query(RoomDatabase.java:323)
        at androidx.room.util.DBUtil.query(DBUtil.java:83)
        at com.android.momoney101.data.ExpenseDao_Impl.getTotalExpense(ExpenseDao_Impl.java:157)
        at com.android.momoney101.repository.ExpenseRepository.getTotal(ExpenseRepository.kt:27)
        at com.android.momoney101.viewmodel.ExpenseViewModel.getTotalExpense(ExpenseViewModel.kt:61)
        at com.android.momoney101.ExpenseList.onCreate(ExpenseList.kt:69)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

我对接下来要做什么有点困惑。感谢您的宝贵时间。

【问题讨论】:

  • 我认为堆栈跟踪很好地解释了它,你到底对什么感到困惑?

标签: android kotlin android-room


【解决方案1】:

堆栈跟踪表明您正在主线程中进行查询,而您必须在后台线程中进行查询,否则您必须使用以下代码。

  private fun buildDatabase(context: Context) = Room.databaseBuilder(
        context.applicationContext,
        AppDatabase::class.java,
        DbConstants.APP_DB_NAME
    ).allowMainThreadQueries().fallbackToDestructiveMigration().build()

【讨论】:

  • 感谢您的帮助。有没有办法在后台线程中执行查询?代码建议有效,但我不确定在主线程中这样做是否是良好的代码实践。
【解决方案2】:

在您的 ViewModel 中,您应该在 viewModelScope 中调用 getTotalExpense()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2022-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多