Search code examples
androidkotlinfilterandroid-recyclerviewsearchview

Having trouble with SearchView, won't filter


Trying to filter my json data from recyclerview with searchview. The recyclerview works fine and I can list out the data, click on them and fetch what i want. But I can't filter the names of the data.

MainAcctivity.kt

class MainActivity : AppCompatActivity() {

// Declare Variables
lateinit var adapter: MainAdapter
lateinit var recyclerView: RecyclerView

val studentDb = BaseDataBase(this)


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    recyclerView = findViewById(R.id.recyclerView)
    recyclerView.layoutManager = LinearLayoutManager(this)
    recyclerView.setHasFixedSize(true)



    fetchJson()
}

private fun fetchJson() {
    println("Attempting to FetchJson")


    val url = HttpUrl.Builder()
        .scheme("https")
        .host("www.noforeignland.com")
        .addPathSegment("home")
        .addPathSegment("api")
        .addPathSegment("v1")
        .addPathSegment("places")
        .build()
        println(url)

    val request = Request.Builder()
        .url(url)
        .cacheControl(CacheControl.Builder().noCache().build())
        .build()

    val client = OkHttpClient()
    client.newCall(request).enqueue(object : Callback {

        override fun onResponse(call: Call, response: Response) {
            val body = response.body?.string()
            println(body)

            val gson = GsonBuilder().create()

            val list = mutableListOf<Properties>()
            when(response.code) {
                200 ->{
                    Thread(Runnable {

                    })
                }
            }

            val homeFeed = gson.fromJson(body, Assigment::class.java)


            runOnUiThread {
                adapter = MainAdapter(homeFeed)
                recyclerView.adapter = adapter

            }
        }

        override fun onFailure(call: Call, e: IOException) {
            println("Failed to execute request")
        }
    })

}


override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    val manager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    val searchItem = menu?.findItem(R.id.searchView2)
    val searchView = searchItem?.actionView as? SearchView

    searchView?.setSearchableInfo(manager.getSearchableInfo(componentName))

    searchView?.setOnQueryTextListener(object: SearchView.OnQueryTextListener {
        override fun onQueryTextSubmit(query: String?): Boolean {
            return false
        }

        override fun onQueryTextChange(newText: String?): Boolean {
            adapter.filter.filter(newText)
            return true
        }
    })
    return true

}

}

MainAdapter.kt

class MainAdapter(var homeFeed: Assigment) : RecyclerView.Adapter<MainAdapter.CustomViewHolder>(), Filterable {

    lateinit var dataFilerList : Assigment


    override fun getItemCount(): Int {
    return homeFeed.features.size
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
    val layoutInflater = LayoutInflater.from(parent?.context)
    val cellForRow = layoutInflater.inflate(R.layout.activity_data, parent, false)
    return CustomViewHolder(cellForRow)
}

override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
    val model = homeFeed.features.get(position)
    holder?.view?.texViewTitle?.text = model.properties.name

    holder?.jsonData = model

}


class CustomViewHolder(val view: View, var jsonData: Feature? = null) : RecyclerView.ViewHolder(view) {




    companion object {
        val title_key = "title"
        val id_key = "id"
        val latitude_key = "latitude"
        val longitude_key = "longitude"
    }

    init {
        view.setOnClickListener {
            val intent = Intent(view.context, CourseDetailActivity::class.java)

            intent.putExtra(title_key, jsonData?.properties?.name)
            intent.putExtra(id_key, jsonData?.properties?.id)

            view.context.startActivity(intent)
        }

        view.gps_view.setOnClickListener{
            val intent = Intent(view.context, MapsActivity::class.java)

            intent.putExtra(title_key, jsonData?.properties?.name)
            intent.putExtra(latitude_key, jsonData?.geometry?.coordinates?.last())
            intent.putExtra(longitude_key, jsonData?.geometry?.coordinates?.first())

            view.context.startActivity(intent)
        }

    }

}


override fun getFilter(): Filter {
    return object : Filter() {
        override fun performFiltering(charString: CharSequence?): FilterResults {
            val charsearch = charString?.toString()?.toLowerCase()
            if (charsearch!!.isEmpty()) {
                dataFilerList = homeFeed
            } else {
                val resultList = ArrayList<Feature>()
                for (row in homeFeed.features) {
                    if (row.properties.name.toLowerCase().contains(charsearch.toLowerCase())
                    ) {
                        resultList.add(row)
                    }
            }
        }

        val filterResult = FilterResults()
        filterResult.values = dataFilerList
        return filterResult
    }

        override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
            dataFilerList = (filterResults.values as? Assigment)!!
            notifyDataSetChanged()
        }


    }
}

}

Assigment.kt

data class Assigment(
val features: List<Feature>,
val type: String

)

I do have some idea of what might be wrong but i'm still pretty new to kotlin.

App screenshot


Solution

  • Looks like your filtered result is stored in dataFilerList. But dataFilerList is not used anywhere in your adapter.

    So instead of "binding" data and getting size from homeFeed, base your displayed data on dataFilerList.

    Initialize dataFilerList as equal to homeFeed.

    class MainAdapter(homeFeed: Assigment) : RecyclerView.Adapter<MainAdapter.CustomViewHolder>(), Filterable {
    
        var dataFilerList: Assigment
        init {
            dataFilerList = homeFeed
        }
    
    
        override fun getItemCount(): Int {
        return dataFilerList.features.size
    }
    
    ...
    
    override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
        val model = dataFilerList.features.get(position)
        holder?.view?.texViewTitle?.text = model.properties.name
    
        holder?.jsonData = model
    
    }
    ...
    

    Let me know if that fixes the issue.

    Edit:

    There's another problem in the filter where you aren't setting the filtered resultList to dataFilerList. So the filtered result is effectively lost.

    override fun getFilter(): Filter {
        return object : Filter() {
            override fun performFiltering(charString: CharSequence?): FilterResults {
                val charsearch = charString?.toString()?.toLowerCase()
                if (charsearch!!.isEmpty()) {
                    dataFilerList = homeFeed
                } else {
                    val resultList = ArrayList<Feature>()
                    for (row in homeFeed.features) {
                        if (row.properties.name.toLowerCase().contains(charsearch.toLowerCase())
                        ) {
                            resultList.add(row)
                        }
                    }
                    dataFilerList = Assigment(resultList, homeFeed.type)
                }
    
                val filterResult = FilterResults()
                filterResult.values = dataFilerList
                return filterResult
            }
    
            override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
                dataFilerList = (filterResults.values as? Assigment)!!
                notifyDataSetChanged()
            }
    
    
        }
    }