CloudFog API Gateway

Limited Time

200+ AI Models Integration Hub

Claim Offer Now
Resolvedandroid

Kotlin 初学者求助:如何修复 RecyclerView 和 SearchView 的搜索过滤问题?🔍

极客老张

1/10/2025

84 views6 likes

嘿,大家好!👋

我最近在搞我的第一个 Android 应用,结果被 RecyclerView 和 SearchView 搞得有点崩溃。😅 我已经能成功加载手机联系人到 RecyclerView 里了,但搜索功能就是不太对劲。看了好多视频教程,还是没搞定。有没有大佬能帮我看看这段代码到底哪里出问题了?🙏

这是我的 MainActivity 代码:

class MainActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks { // SearchView 和 RecyclerView private lateinit var recyclerView: RecyclerView private lateinit var searchView: SearchView private var mList = ArrayList<ContactModel>() private lateinit var adapter: RCVAdapter private lateinit var binding: ActivityMainBinding var arrayList: ArrayList<ContactModel> = arrayListOf() var rcvAdapter: RCVAdapter = RCVAdapter(arrayList) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) // 初始化 RecyclerView 和 SearchView recyclerView = findViewById(R.id.rcvContact) searchView = findViewById(R.id.TxtSearch) recyclerView.setHasFixedSize(true) recyclerView.layoutManager = LinearLayoutManager(this) // 设置适配器 adapter = RCVAdapter(arrayList) recyclerView.adapter = adapter if (checkContactPermissions()) { binding.apply { rcvContact.apply { layoutManager = LinearLayoutManager(this@MainActivity) adapter = RCVAdapter(arrayList) } } // 加载联系人 getContacts() } // 设置搜索监听器 searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { return false } override fun onQueryTextChange(newText: String?): Boolean { filterList(newText) return true } }) } // 搜索过滤 private fun filterList(query: String?) { if (query != null) { val filteredList = arrayList // 这里应该是个新列表 for (i in mList) { if (i.contname.lowercase(Locale.ROOT).contains(query)) { filteredList.add(i) } } if (filteredList.isEmpty()) { Toast.makeText(this, "No Contact found!", Toast.LENGTH_SHORT).show() } else { adapter.setFilteredList(filteredList) // 这里应该传 filteredList } } } private fun getContacts() { // 加载联系人逻辑 } }

这是我的 RCVAdapter 代码:

class RCVAdapter(var contactList: ArrayList<ContactModel>) : RecyclerView.Adapter<RCVAdapter.MyViewHolder>() { inner class MyViewHolder(val binding: ItemContactBinding) : RecyclerView.ViewHolder(binding.root) { val contid = binding.TxtContID val contname = binding.TxtContName val contno = binding.TxtContNo val contphoto = binding.ImgContPhoto val contemail = binding.TxtContEmail } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { return MyViewHolder( ItemContactBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val item = contactList[position] holder.binding.TxtContID.text = item.contid.toString() holder.binding.TxtContName.text = item.contname holder.binding.TxtContNo.text = item.contnumber if (contactList[position].contPhoto != null) holder.binding.ImgContPhoto.setImageBitmap(contactList[position].contPhoto) else holder.binding.ImgContPhoto.setImageDrawable(ContextCompat.getDrawable(holder.itemView.context, R.drawable.ic_people_24)) holder.binding.TxtContEmail.text = item.contemail } override fun getItemCount(): Int = contactList.size fun setFilteredList(contactList: List<ContactModel>) { this.contactList = contactList as ArrayList<ContactModel> notifyDataSetChanged() } }

还有我的 ContactModel 类:

data class ContactModel( var contid: String = "", var contname: String = "", var contnumber: String = "", var contPhoto: Bitmap? = null, var contemail: String = "", )

我觉得问题可能出在 filterList 方法里,特别是 filteredList 的使用上。🤔 我试着用一个新的 ArrayList 来存储过滤后的结果,但好像没什么用。有没有人能帮我指出问题所在?谢谢!🙏

PS: 我是从 VB.NET 转过来的,对 Kotlin 还在摸索中,求轻喷!😅


标签:Android、Kotlin、RecyclerView、SearchView、初学者问题

1 Answers

全栈David

1/10/2025

Best Answer3

Answer #1 - Best Answer

嘿,你好啊!👋 我太理解你遇到的 RecyclerView 和 SearchView 的问题了 - 我之前也栽在这上面!别担心,我们一起来看看怎么解决这个问题。

问题分析

你提到的问题主要出在 filterList 方法中。你在过滤联系人时,使用了原始的 arrayList,这会导致在每次搜索时都往同一个列表中添加元素,结果就是列表会不断增长,而不是替换为新的过滤结果。

解决方案

我们需要确保在每次搜索时,创建一个新的列表来存储过滤后的结果,并将其传递给适配器。这样可以避免重复添加的问题。下面是修改后的代码:

// ... existing code ... private fun filterList(query: String?) { if (query != null) { val filteredList = ArrayList<ContactModel>() // 创建一个新的列表 for (i in mList) { if (i.contname.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT))) { filteredList.add(i) } } if (filteredList.isEmpty()) { Toast.makeText(this, "No Contact found!", Toast.LENGTH_SHORT).show() } else { adapter.setFilteredList(filteredList) // 传递新的过滤列表 } } } // ... existing code ...

代码解释

  1. 创建新列表:在 filterList 方法中,使用 ArrayList<ContactModel>() 创建一个新的列表 filteredList,用于存储符合搜索条件的联系人。

  2. 大小写不敏感搜索:在比较时,将 queryi.contname 都转换为小写,以实现大小写不敏感的搜索。

  3. 更新适配器:调用 adapter.setFilteredList(filteredList),将过滤后的列表传递给适配器。

个人经验分享

我记得第一次做搜索功能时,也遇到了类似的问题。一个小技巧是始终确保在每次操作时,数据源是最新的。这样可以避免很多意想不到的错误。

常见错误提醒

  • 确保在 onCreate 中初始化的 mList 是完整的联系人列表,而不是空的。
  • 检查 getContacts() 方法,确保它正确地填充了 mList

希望这些建议能帮到你!如果还有其他问题,随时问我哦!继续加油,Kotlin 的学习曲线虽然有点陡,但你一定能搞定的!🚀

如果你有其他问题或者需要进一步的帮助,随时联系我!😊

CloudFog API Gateway 🔥 New User Special

💥 New User Offer: Get $1 Credit for ¥0.5

Claim Offer Now