如何在 Room 中使用带有 LiveData 和 ViewModel 的 SearchView

How to use SearchView with LiveData and ViewModel in Room

我想使用 SearchView 在 room db 中搜索一些元素,我对此有疑问,因为我不能在 RecyclerViewAdapter 中使用 getFilter,因为我有 ViewModel,也许谁知道如何在一个项目中组合所有这些元素。
我搜索使用 Transormations.switchMap 的一种方式。但是我连接不上。

ProductViewModel

class ProductViewModel(application: Application) : AndroidViewModel(application) {
    private val repository: ProductRepository

    val allProducts: LiveData<List<ProductEntity>>
    private val searchStringLiveData = MutableLiveData<String>()

    init {
        val productDao = ProductsDB.getDatabase(application, viewModelScope).productDao()
        repository = ProductRepository(productDao)
        allProducts = repository.allProducts
        searchStringLiveData.value = ""
    }

    fun insert(productEntity: ProductEntity) = viewModelScope.launch {
        repository.insert(productEntity)
    }


    val products = Transformations.switchMap(searchStringLiveData) { string ->
        repository.getAllListByName(string)

    }

    fun searchNameChanged(name: String) {
        searchStringLiveData.value = name
    }



}

ProductDao

interface ProductDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertProduct(productEntity: ProductEntity)

    @Query("SELECT * from products")
    fun getListAllProducts(): LiveData<List<ProductEntity>>


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

    @Query("SELECT * FROM products where product_name_ent LIKE :name or LOWER(product_name_ent) like LOWER(:name)")
    fun  getListAllByName(name: String):LiveData<List<String>>

}

ProductDao

@Query("SELECT * FROM products where product_name_ent LIKE :name or LOWER(product_name_ent) like LOWER(:name)")
            fun  getListAllByName(name: String):LiveData<List<ProductEntity>>

你 dao 中的这个方法应该 return LiveData<List<ProductEntity>> 而不是 LiveData<List<String>>,因为这个查询从实体中选择 everything (*) 不是特定的列。

它类似于 (@Query("SELECT * from products") fun getListAllProducts():LiveData<List<ProductEntity>>)

ProductViewModel

    class ProductViewModel(application: Application) : AndroidViewModel(application) {
        private val repository: ProductRepository
        init {
            val productDao = ProductsDB.getDatabase(
                application,
                viewModelScope
            ).productDao()
            repository = ProductRepository(productDao)
        }


        private val searchStringLiveData = MutableLiveData<String>("") //we can add initial value directly in the constructor
        val allProducts: LiveData<List<ProductEntity>>=Transformations.switchMap(searchStringLiveData)
        {
            string->
            if (TextUtils.isEmpty(string)) {
                repository.allProducts()
            } else {
                repository.allProductsByName(string)
            }
        }


        fun insert(productEntity: ProductEntity) = viewModelScope.launch {
            repository.insert(productEntity)
        }

        fun searchNameChanged(name: String) {
            searchStringLiveData.value = name
        }


    }

Repository

...使用您拥有的其他方法,添加以下内容:

fun allProducts():LiveData<List<ProductEntity>>=productDao.getListAllProducts()
fun allProductsByNames(name:String):LiveData<List<ProductEntity>>=productDao.getListAllByName(name)

In Your Activity Or Fragment Where you have the recyclerview adapter

在 onCreate() 内部(如果它是 activity)

viewModel.allProducts.observe(this,Observer{products->
//populate your recyclerview here
})

onActivityCreated(if it is a fragment)
       viewModel.allProducts.observe(viewLifecycleOwner,Observer{products->
    //populate your recyclerview here
    })

现在给 searchView 设置一个侦听器,每次用户提交查询时,调用 viewModel.searchNameChanged(// pass the new value)

希望对您有所帮助

此致,