【问题标题】:How to implement multiple queries with room database?如何使用房间数据库实现多个查询?
【发布时间】:2021-04-03 04:18:55
【问题描述】:

我正在使用带有 MVVM 模式的房间数据库创建一个 android 应用程序,问题是我在获取数据时无法使用多个查询。我可以获取一次数据,但是我不能再这样做了。

DAO 接口:

@Dao
interface StockDao {

    @Insert
    suspend fun insert(stock:Stock)

    @Update
    suspend fun update(stock:Stock)

    @Delete
    suspend fun delete(stock:Stock)

    @Query("DELETE FROM stock_table")
    suspend fun deleteAll()

    @Query("SELECT * FROM stock_table")
    fun selectAll():Flow<List<Stock>>

    @Query("SELECT * FROM stock_table WHERE isFinished = 0")
    fun selectAllUnfinished(): Flow<List<Stock>>

    @Query("SELECT * FROM stock_table WHERE isFinished = 1")
    fun selectAllFinished():Flow<List<Stock>>

    @Query("SELECT * FROM stock_table ORDER BY totalSpent DESC")
    fun selectAllOrderByDesc():Flow<List<Stock>>

    @Query("SELECT * FROM stock_table ORDER BY totalSpent ASC")
    fun selectAllOrderByAsc():Flow<List<Stock>>

}

存储库:

class StockRepository(private val stockDao: StockDao) {

    private lateinit var allStock: Flow<List<Stock>>


    suspend fun insert(stock: Stock) {

        stockDao.insert(stock)

    }

    suspend fun update(stock: Stock) {

        stockDao.update(stock)

    }

    suspend fun delete(stock: Stock) {

        stockDao.delete(stock)

    }

    suspend fun deleteAll() {

        stockDao.deleteAll()

    }

    fun selectAll(): Flow<List<Stock>> {

        allStock = stockDao.selectAll()

        return allStock

    }

    fun selectAllOrderByDesc(): Flow<List<Stock>> {

        allStock = stockDao.selectAllOrderByAsc()

        return allStock

    }

    fun selectAllOrderByAsc(): Flow<List<Stock>> {

        allStock = stockDao.selectAllOrderByAsc()

        return allStock

    }

    fun selectAllFinished(): Flow<List<Stock>> {

        allStock = stockDao.selectAllFinished()

        return allStock

    }

    fun selectAllUnfinished(): Flow<List<Stock>> {

        allStock = stockDao.selectAllUnfinished()

        return allStock

    }


}

Viewmodel 类:

class StockViewModel(private val repo: StockRepository) : ViewModel() {

    companion object {

        const val ALL = 0
        const val ORDER_BY_DESC = 1
        const val ORDER_BY_ASC = 2
        const val FINISHED = 3
        const val UNFINISHED = 4

    }

    var allStocks = repo.selectAll().asLiveData()


    fun insert(stock: Stock) = viewModelScope.launch {
        repo.insert(stock)
    }

    fun update(stock: Stock) = viewModelScope.launch {
        repo.update(stock)
    }

    fun delete(stock: Stock) = viewModelScope.launch {
        repo.delete(stock)
    }

    fun deleteAll() = viewModelScope.launch {
        repo.deleteAll()
    }

    fun selectAllStockWithFilter(filter: Int): LiveData<List<Stock>> {

        when (filter) {

            ALL -> allStocks = repo.selectAll().asLiveData()
            ORDER_BY_DESC -> allStocks = repo.selectAllOrderByDesc().asLiveData()
            ORDER_BY_ASC -> allStocks = repo.selectAllOrderByAsc().asLiveData()
            FINISHED -> allStocks = repo.selectAllFinished().asLiveData()
            UNFINISHED -> allStocks = repo.selectAllUnfinished().asLiveData()
        }

        return allStocks

    }


    class StockViewModelFactory(private val repo: StockRepository) : ViewModelProvider.Factory {

        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(StockViewModel::class.java)) {
                @Suppress("UNCHECKED_CAST")
                return StockViewModel(repo) as T
            }

            throw IllegalArgumentException("Unknown viewModel class")
        }

    }


}

应用类:

class FinanceApplication :Application(){

    private val database by lazy {  FinanceDatabase.getInstance(this)}

    val stockRepository by lazy { StockRepository(database.stockDao()) }
}


使用此视图模型的活动:

class StocksActivity : AppCompatActivity() {

    //Layout components
    private lateinit var binder: ActivityStocksBinding
    private lateinit var recyclerView: RecyclerView
    private lateinit var recyclerViewAdapter: StockAdapter

    //ViewModel
    private val viewModel: StockViewModel by viewModels {
        StockViewModel.StockViewModelFactory((application as FinanceApplication).stockRepository)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binder = ActivityStocksBinding.inflate(layoutInflater)
        setContentView(binder.root)
    
        fetchStocks()


    }

    private fun fetchStocks() {


        viewModel.allStocks.observe(this) {

            recyclerViewAdapter.submitList(it)

        }


    }

    private fun initRecyclerViewLayout() {


        val recyclerViewLayoutBinder = binder.includedLayout

        recyclerView = recyclerViewLayoutBinder.stocksRecyclerView
        recyclerViewAdapter = StockAdapter(this)
        recyclerView.adapter = recyclerViewAdapter
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.setHasFixedSize(true)


    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {

        menuInflater.inflate(R.menu.menu_stock_toolbar, menu)

        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {

        when (item.itemId) {

            R.id.menu_stock_toolbar_filter_all -> viewModel.selectAllStockWithFilter(StockViewModel.ALL)
            R.id.menu_stock_toolbar_filter_maior_menor ->  viewModel.selectAllStockWithFilter(StockViewModel.ORDER_BY_DESC)
            R.id.menu_stock_toolbar_filter_menor_maior -> viewModel.selectAllStockWithFilter(StockViewModel.ORDER_BY_ASC)
            R.id.menu_stock_toolbar_filter_finalized -> viewModel.selectAllStockWithFilter(StockViewModel.FINISHED)
            R.id.menu_stock_toolbar_filter_opened -> viewModel.selectAllStockWithFilter(StockViewModel.UNFINISHED)

        }

        return true
        
        //NOTHIN HAPPENS AFTER CHOOSING ONE

    }

} 

当我进入活动时,所有数据都会正常获取,但是当我单击菜单项对其应用一些过滤器时,什么也没有发生,数据不会改变。我该如何解决这个问题?

【问题讨论】:

  • StocksActivity.fetchStocks() 中,最初的“全部”结果通过observe()'ing ViewModel 返回的LiveData 显示。从选项菜单中选择后,新的过滤结果observe()'ed 怎么样?
  • @homerman 当我点击一个菜单项时,StocksActivity.fetchStocks() 方法将`allStock` 变量从StocksViewmodel.. 至少这是意图,还是我想错了?跨度>

标签: android android-studio android-room android-mvvm


【解决方案1】:

allStocks 可能看起来是动态的,因为它是LiveData,但请记住,它仍然是对内存中对象的引用。创建StocksActivity 时,它会观察allStocks 的初始状态。为简单起见,假设allStocks 指向内存中地址为“A”的对象。当selectAllStockWithFilter() 最终被调用时,allStocks 句柄被更新以指向一个新的LiveData 实例,该实例位于内存中的地址“B”处。您面临的问题是StocksActivity 仍在观察“A”。没有任何信息表明 allStocks 句柄本身已被更改。

解决此问题的一种方法是将allStocks 更改为MutableLiveData 的实例。随后,每当这个allStocks 的内容应该被更新,而不是重新分配allStocks,你会更新它的内部“值”。这允许ViewModel 通过StocksActivity 正在观察的同一个LiveData 对象实例抽取新的/更新的值。

类似这样的:

class StockViewModel(private val repo: StockRepository) : ViewModel() {

    ...

    val allStocks = MutableLiveData<List<Stock>>().apply { value = repo.selectAll() }


    ...

    fun selectAllStockWithFilter(filter: Int) {
        when (filter) {
            ALL -> allStocks.postValue(repo.selectAll())
            ORDER_BY_DESC -> allStocks.postValue(repo.selectAllOrderByDesc())
            ORDER_BY_ASC -> allStocks.postValue(repo.selectAllOrderByAsc())
            FINISHED -> allStocks.postValue(repo.selectAllFinished())
            UNFINISHED -> allStocks.postValue(repo.selectAllUnfinished())
        }
    }

    ...

}

【讨论】:

    猜你喜欢
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 2021-05-21
    相关资源
    最近更新 更多