如何解决如何使用房间数据库实现多个查询?
我正在使用带有 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
}
}
视图模型类:
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
}
}
当我进入活动时,所有数据都被正常获取,但是当我点击一个菜单项对其应用一些过滤器时,没有任何反应,数据没有改变。我该如何解决这个问题?
解决方法
allStocks
可能看起来是动态的,因为它是 LiveData
,但请记住,它仍然是对内存中对象的引用。创建 StocksActivity
时,它会观察 allStocks
的初始状态。为简单起见,假设 allStocks
指向内存中地址为“A”的对象。当 selectAllStockWithFilter()
最终被调用时,allStocks
句柄被更新以指向位于地址“B”的内存中的 LiveData
的新实例。您面临的问题是 StocksActivity
仍在观察“A”。没有任何信息表明 allStocks
句柄本身已被更改。
解决此问题的一种方法是将 allStocks
更改为 MutableLiveData
的实例。随后,每当此 allStocks
的内容应更新时,您将更新它的内部“值”,而不是重新分配 allStocks
。这允许 ViewModel
通过 LiveData
正在观察的同一个 StocksActivity
对象实例抽取新的/更新的值。
像这样:
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())
}
}
...
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。