Android SearchView - 没有错误但是无法过滤 recyclerView

Android SearchView - No errors however unable to filter recyclerView

我正在尝试使用工具栏中的 SearchView 过滤 RecyclerView。我没有遇到任何错误,table 和搜索栏似乎显示正确。但是,当我在搜索栏中键入内容时,table 不会过滤。

最初我以为我可能没有通知数据集已更改,但此方法调用存在于 publishResults 中。

可能是因为数据集不是全局变量?我认为最好在这里避免使用全局变量...

//Models
package com.example.imperialvisualisationsandroid

class DataModel(val Visualisations: List<Visualisation>)

class Visualisation(val id: Int, val name: String, val info: String, val url_name: String, val tags: String, val imageURL: String, val gifURL: String)



//MainActivity

package com.example.imperialvisualisationsandroid

import android.app.SearchManager
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.provider.ContactsContract
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.SearchView
import android.view.Menu
import android.view.MenuItem
import com.google.gson.GsonBuilder
import com.klinker.android.peekview.PeekViewActivity
import kotlinx.android.synthetic.main.activity_main.*
import okhttp3.*
import java.io.IOException

public class MainActivity : AppCompatActivity() {

    // data variable - changed only once during data decode
    var data: DataModel = DataModel(Visualisations = emptyList())

    private var searchView: SearchView? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        recyclerView_main.layoutManager = LinearLayoutManager(this)

        decodeJSON()

    }

    //TABLE SETUP



    fun decodeJSON() {

        //var data: DataModel?

        val jsonURL = "__insert url here__"

        val request = Request.Builder().url(jsonURL).build()

        val client = OkHttpClient()

        client.newCall(request).enqueue(object: Callback {

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

                val gson = GsonBuilder().create()

                //class.java??
                data = gson.fromJson(jsonBody, DataModel::class.java)
                println("JSON FETCH SUCCESSFUL")

                //cannot return data here as return needs to be unit (cannot specify model to DataModel)
                //Have to update UI on UI thread
                runOnUiThread {
                    recyclerView_main.adapter = MainAdapter(data)
                }

            }

            override fun onFailure(call: Call, e: IOException) {
                println("JSON FETCH FAILED")
                println(e)
            }
        })


    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.options_menu, menu)


        val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
        // ???
        searchView = menu?.findItem(R.id.search)?.actionView as SearchView

        searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))

        searchView!!.maxWidth = Integer.MAX_VALUE

        searchView!!.setOnQueryTextListener(object: SearchView.OnQueryTextListener {

            override fun onQueryTextSubmit(query: String?): Boolean {
                MainAdapter(data).filter.filter(query)
                return false
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                MainAdapter(data).filter.filter(newText)
                return false
            }
        })

        return true

    }

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {

        val id = item?.itemId
        return if (id == R.id.search){
            true
        } else super.onOptionsItemSelected(item)
    }

}



//MainAdapter

package com.example.imperialvisualisationsandroid

import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import com.bumptech.glide.Glide
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.visualisation_cell.view.*

class MainAdapter(val data: DataModel) : RecyclerView.Adapter<ViewHolder>(), Filterable {

    val visualisations = data.Visualisations

    var searchVisualisations = data.Visualisations.toMutableList()

    override fun getItemCount(): Int {
        return searchVisualisations.count()
    }

    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
        val layoutInflater = LayoutInflater.from(p0.context)
        val cellForRow = layoutInflater.inflate(R.layout.visualisation_cell, p0, false)
        return ViewHolder(cellForRow)
    }


    override fun onBindViewHolder(p0: ViewHolder, p1: Int) {

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
        super.onBindViewHolder(holder, position, payloads)

        holder.itemView.setBackgroundColor(Color.WHITE)

        val selectedVisualisation = searchVisualisations.get(position)

        holder.view.titleTextView.text = searchVisualisations[position].name
        holder.view.infoTextView.text = searchVisualisations[position].info

        //PICASSO
        //Picasso.get().load(visualisations[position].imageURL).into(holder.view.VisualisationImageView)


        //GLIDE
        val context = holder.view.context
        Glide.with(context)
            .load(searchVisualisations[position].imageURL)
            .into(holder.view.VisualisationImageView)

        holder.selectedVisualisation = selectedVisualisation

    }


    override fun getFilter(): Filter {
        return object: Filter() {

            override fun performFiltering(p0: CharSequence?): FilterResults {
                val searchQuery = p0.toString().toLowerCase()

                var filteredVisualisations = ArrayList<Visualisation>()

                if (searchQuery.isEmpty()) {
                    filteredVisualisations.addAll(visualisations)
                } else {
                    for (vis in visualisations) {

                        var visString = (vis.name + " " + vis.info + " " + vis.tags).toLowerCase()

                        if (visString.contains(searchQuery)) {
                            filteredVisualisations.add(vis)
                        }
                    }

//                    searchVisualisations.clear()
//                    searchVisualisations.addAll(filteredVisualisations)

                }

                val filterResults = FilterResults()
                filterResults.count = filteredVisualisations.size
                filterResults.values = filteredVisualisations
                return filterResults
            }

            override fun publishResults(p0: CharSequence?, p1: FilterResults?) {
                searchVisualisations = p1?.values as ArrayList<Visualisation>
                notifyDataSetChanged()
            }
        }
    }
}

class ViewHolder(val view: View, var selectedVisualisation: Visualisation? = null) : RecyclerView.ViewHolder(view) {

    companion object {
        val SelectedVisualisationTitle = "SelectedVisualisationTitle"
        val SelectedVisualisationWebURL = "SelectedVisualisationWebURL"
    }

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

            intent.putExtra(SelectedVisualisationTitle, selectedVisualisation?.name)
            intent.putExtra(SelectedVisualisationWebURL, selectedVisualisation?.url_name)

            view.context.startActivity(intent)
        }

//        view.setOnLongClickListener {
////            val intent = Intent(view.context, GIFDetailActivity::class.java)
////            view.context.startActivity(intent)
////        }
    }

}

//Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.imperialvisualisationsandroid">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data android:name="android.app.searchable"
                       android:resource="@xml/searchable">

            </meta-data>

        </activity>

        <activity android:name=".VisualisationDetailActivity"
                  android:theme="@style/AppTheme.DetailTheme"
            android:label="Visualisation Detail"
                  android:launchMode="singleTop">

            <!--Back button support-->

            <meta-data android:name="android.support.PARENT_ACTIVITY"
                       android:value=".MainActivity">
            </meta-data>
        </activity>
    </application>

</manifest>


//Options Menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".MainActivity">
    <item android:id="@+id/search"
          android:title="@string/search_title"
          android:icon="@drawable/ic_search_api_holo_dark"
          app:showAsAction="collapseActionView|ifRoom"
          app:actionViewClass="android.support.v7.widget.SearchView"
    />
</menu>


//searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
            android:label="@string/app_name"
            android:hint="@string/search_hint"
            android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"/>

如有任何帮助,我们将不胜感激

在您的搜索监听器中

MainAdapter(data).filter.filter(query)

您正在创建执行过滤器的适配器的新实例。因此附加到 RecyclerView 的适配器对象与具有过滤结果的适配器对象不同。

你应该这样做

(recyclerView_main.adapter  as Filterable).filter.filter(query)