Android 如何使用房间数据库实现多个查询?
我正在使用MVVM模式的room数据库创建一个android应用程序,问题是我在获取数据时不能使用多个查询。我可以提取一次数据,但是我不能再这样做了 DAO接口:Android 如何使用房间数据库实现多个查询?,android,android-studio,android-room,android-mvvm,Android,Android Studio,Android Room,Android Mvvm,我正在使用MVVM模式的room数据库创建一个android应用程序,问题是我在获取数据时不能使用多个查询。我可以提取一次数据,但是我不能再这样做了 DAO接口: @Dao interface StockDao { @Insert suspend fun insert(stock:Stock) @Update suspend fun update(stock:Stock) @Delete suspend fun delete(stock:St
@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
}
}
使用此viewmodel的活动:
@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
}
}
当我进入“活动”时,所有数据都会正常获取,但当我单击某个菜单项对其应用一些过滤器时,什么也没有发生,数据不会更改。如何修复此问题?
所有股票
可能看起来是动态的,因为它是LiveData
,但请记住,它仍然是对内存中对象的引用。创建StocksActivity
时,它会在初始状态下观察allStocks
。为了简单起见,假设allStocks
指向内存中地址为“A”的对象。最终调用selectAllStockWithFilter()
时,会更新allStocks
句柄,以指向位于地址“B”的内存中的LiveData
的新实例。您面临的问题是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())
}
}
...
}
类StockViewModel(私有val repo:StockRepository):ViewModel(){
...
val allStocks=MutableLiveData().apply{value=repo.selectAll()}
...
乐趣选择AllStockWithFilter(过滤器:Int){
何时(过滤器){
ALL->allStocks.postValue(repo.selectAll())
ORDER_BY_DESC->allStocks.postValue(repo.selectAllOrderByDesc())
订单由\u ASC->allStocks.postValue(repo.selectAllOrderBySC())
FINISHED->allStocks.postValue(repo.selectAllFinished())
UNFINISHED->allStocks.postValue(repo.selectAllUnfinished())
}
}
...
}
在StocksActivity.fetchStocks()
中,初始的“所有”结果通过observe()
”显示,并显示ViewModel返回的LiveData。从选项菜单中选择后,新的过滤结果是如何过滤的?@homerman当我单击菜单项时,方法StocksActivity.fetchStocks()
会更改StocksViewmodel
中的'allStock'变量。至少这是我的意图,还是我想错了?