Kostya Lotysh
Kostya Lotysh

Reputation: 39

How to use SearchView with LiveData and ViewModel in Room

i want to use SearchView for search some element in room db and i have a problem with this because i cant use getFilter in RecyclerViewAdapter because i have ViewModel maybe whoes know how to combine all of this element in one project.
I search one way use Transormations.switchMap. But I couldn’t connect them.

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>>

}

Upvotes: 0

Views: 2553

Answers (1)

Hady Salhab
Hady Salhab

Reputation: 583

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>>

This Method in your dao should return LiveData<List<ProductEntity>> and not LiveData<List<String>>, because this query selects everything (*) from the entity and not a specific column.

it is similar to (@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

...with the other method that you have, add the following:

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

inside onCreate() (if it is an activity)

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

or

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

Now set a listener to the searchView, everytime the user submit the query , call viewModel.searchNameChanged(// pass the new value)

Hope this helps

Regards,

Upvotes: 6

Related Questions