I have a Room
database (with dao), a Repository
, a ViewModel
a RecyclerView
and an Adapter
interacting with each other.
Right now the RecyclerView
just displays all the item in my ReferenceItem
table.
I want to add a Search Bar at the top and filter the results in the RecyclerView
.
Here is how I implement my RecyclerView
and its Adapter
in the Fragment
:
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Init la searchVal
searchVal = ""
// Set RecyclerView
setRecyclerView(view)
// Observe LiveData of all items
viewModel.getFilteredReferenceItem(searchVal).observe(viewLifecycleOwner, Observer {
refAdapter.referenceItems = viewModel.sortReferenceItemList(it)
refAdapter.notifyDataSetChanged()
})
The parameter .referenceItems
in the refAdapter
is what contains the list of item I want to display.
.referenceItems
is of type MutableList<AdapterReferenceItem>
The getFilteredReferenceItem()
method looks like this in the dao
:
@Query(value="SELECT * FROM reference_items WHERE reference_item_name LIKE '%' || :searchVal || '%' ORDER BY category ASC, reference_item_name ASC")
fun getFilteredReferenceItem(searchVal : String): LiveData<List<ReferenceItem>>
It returns a LiveData
.
The sortReferenceItemList()
is to add Headers to certain item group. This is for aesthetic only. BUT, it takes a MutableList
as argument and not a LiveData
.
Now, I do not understand how the "it" argument work in :
refAdapter.referenceItems = viewModel.sortReferenceItemList(it)
I do not understand how "it" can be a MutableList
when all I pass is a LiveData
.
Now for the Search Bar, here is what I have so far. I am trying to change the value of searchVal
to get the LiveData
to update... but nothing happens.
//SearchView
searchView = view.findViewById<SearchView>(R.id.search_ref)
searchView.setOnQueryTextListener(object : OnQueryTextListener,
SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
TODO("Not yet implemented")
}
@SuppressLint("NotifyDataSetChanged")
override fun onQueryTextChange(newText: String?): Boolean {
searchVal = if (newText != null) {
newText.toString()
} else{
""
}
refAdapter.notifyDataSetChanged()
return true
}
})
P.S: I am not a developer. I developed this app 3 years ago and never touched Kotlin or Android Studio ever since. But I think this is a nice update to my small personal app that I would love to finish.
well, you seems to recall everything but missed few things here and there.
refAdapter.referenceItems = viewModel.sortReferenceItemList(it)
The "it" here refers to the list the livedata holds .i.e
LiveData<List<ReferenceItem>>
You are trying to make a search functionality, here how you can do it in the viewModel
private val _query = MutableLiveData<String>("")
val query: LiveData<String> = _query
val filteredItems: LiveData<List<ReferenceItem>> = Transformations.switchMap(_query) { query ->
dao.getFilteredReferenceItem(query)
}
fun setSearchQuery(query: String) {
_query.value = query
}
In the MainActivity,
searchView = findViewById(R.id.searchView)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
query?.let {
viewModel.setSearchQuery(it)
}
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
newText?.let {
viewModel.setSearchQuery(it)
}
return true
}
})
viewModel.filteredItems.observe(this) { filteredList ->
// adapter.submitList(filteredList) , its better if you extend your adapter with ListAdapter so that you don't need call notifyDataSetChanged.
refAdapter.referenceItems = filteredList
refAdapter.notifyDataSetChanged()
}