0

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.

1 Answer 1

1

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()
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, it works. I had to tweak it a bit, but the philosophy works !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.