RecyclerView点击卡片无法启动新Activity问题求助
问题描述
我正在实现点击RecyclerView中的卡片打开AdminProspectsDetails Activity查看潜在客户(Prospect)详情的功能,但点击卡片时没有任何Activity启动。目前仅需验证能否打开新页面,还未在详情页填充数据,不清楚问题出在哪里。相关代码如下:
AdminProspects类
package ml2v.demenagement.all.android.ui.interfaces import ProspectAdminAdapter import android.content.Intent import android.os.Bundle import android.widget.Switch import android.widget.Toast import androidx.activity.ComponentActivity import androidx.recyclerview.widget.RecyclerView import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.ktx.firestore import com.google.firebase.ktx.Firebase import jp.wasabeef.recyclerview.animators.SlideInUpAnimator import ml2v.demenagement.all.android.data.model.CardClickListener import ml2v.demenagement.all.android.data.model.PROSPECT_ID_EXTRA import ml2v.demenagement.all.android.data.model.Prospect import ml2v.demenagement.app.android.R import java.util.Objects class AdminProspects() : ComponentActivity(), CardClickListener { private lateinit var recyclerView: RecyclerView private val prospectList = mutableListOf<Prospect>() private var filteredList = mutableListOf<Prospect>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_admin_prospects) actionBar?.hide() recyclerView = findViewById<RecyclerView>(R.id.prospects_views) val adapter = ProspectAdminAdapter(prospectList) adapter.setCardClickListener(this) recyclerView.adapter = adapter val switchWaiting: Switch = findViewById(R.id.waiting) val switchInProgress: Switch = findViewById(R.id.in_progress) val switchValidate: Switch = findViewById(R.id.validate) val switchPro: Switch = findViewById(R.id.switch_pro) val switchPerso: Switch = findViewById(R.id.switch_perso) var isWaitingSelected = false var isInProgressSelected = false var isValidatedSelected = false // BDD val db = Firebase.firestore val prospectsCollection = db.collection("demenagement") recyclerView = findViewById<RecyclerView>(R.id.prospects_views) prospectsCollection.get().addOnSuccessListener { documents -> for (document in documents) { val prospect = document.data // Traitez les données du prospect ici val categorie = prospect["categorie"] as String val email = prospect["mail"] as String val nom = prospect["nom"] as String val siret = prospect["siret"] as String val tel = prospect["tel"] as String val type = prospect["type"] as String val status = prospect["status"] as String val usersuid = prospect["users"] as String //Récupération du nom de l'utilisateur en fonction de son uid val usersCollection = db.collection("users") usersCollection.document(usersuid).get().addOnSuccessListener { document -> val userName = document.getString("nom").toString() val newProspect = Prospect(categorie, email, nom, siret, tel, type, userName, status) prospectList.add(newProspect) val adapter = (prospectList) recyclerView.adapter = ProspectAdminAdapter(adapter) recyclerView.itemAnimator = SlideInUpAnimator() } } } switchWaiting.setOnCheckedChangeListener { _, isChecked -> isWaitingSelected = isChecked switchInProgress.isClickable = false switchValidate.isClickable = false if (isChecked) { // Filtrer la liste prospectList pour ne garder que les prospects en attente filteredList = prospectList.filter { prospect -> prospect.status == "En attente" } as MutableList<Prospect> recyclerView.adapter = ProspectAdminAdapter(filteredList as MutableList<Prospect>) if(filteredList.size == 0){ Toast.makeText( this@AdminProspects, "Liste vide pour le moment", Toast.LENGTH_SHORT ).show() } } else { // Rétablir la liste complète prospectList recyclerView.adapter = ProspectAdminAdapter(prospectList) switchInProgress.isClickable = true switchValidate.isClickable = true } } switchInProgress.setOnCheckedChangeListener { _, isChecked -> isInProgressSelected = isChecked switchWaiting.isClickable = false switchValidate.isClickable = false if (isChecked) { // Filtrer la liste prospectList pour ne garder que les prospects en attente filteredList = prospectList.filter { prospect -> prospect.status == "En progression" } as MutableList<Prospect> recyclerView.adapter = ProspectAdminAdapter(filteredList as MutableList<Prospect>) if(filteredList.size == 0){ Toast.makeText( this@AdminProspects, "Liste vide pour le moment", Toast.LENGTH_SHORT ).show() } } else { // Rétablir la liste complète prospectList recyclerView.adapter = ProspectAdminAdapter(prospectList) switchWaiting.isClickable = true switchValidate.isClickable = true } } switchValidate.setOnCheckedChangeListener { _, isChecked -> isValidatedSelected = isChecked switchWaiting.isClickable = false switchInProgress.isClickable = false if (isChecked) { // Filtrer la liste prospectList pour ne garder que les prospects en attente filteredList = prospectList.filter { prospect -> prospect.status == "Validé" } as MutableList<Prospect> recyclerView.adapter = ProspectAdminAdapter(filteredList as MutableList<Prospect>) if(filteredList.size == 0){ Toast.makeText( this@AdminProspects, "Liste vide pour le moment", Toast.LENGTH_SHORT ).show() } } else { // Rétablir la liste complète prospectList recyclerView.adapter = ProspectAdminAdapter(prospectList) switchWaiting.isClickable = true switchInProgress.isClickable = true } } switchPro.setOnCheckedChangeListener{ _, isChecked -> switchPerso.isClickable = false if(isChecked){ // Filtrer la liste prospectList pour ne garder que les prospects en attente filteredList = filteredList.filter { prospect -> prospect.type == "Professionnel" } as MutableList<Prospect> recyclerView.adapter = ProspectAdminAdapter(filteredList as MutableList<Prospect>) if(filteredList.size == 0){ Toast.makeText( this@AdminProspects, "Liste vide pour le moment", Toast.LENGTH_SHORT ).show() } }else{ recyclerView.adapter = ProspectAdminAdapter(prospectList) switchPerso.isClickable = true } } switchPerso.setOnCheckedChangeListener{ _, isChecked -> switchPro.isClickable = false if(isChecked){ // Filtrer la liste prospectList pour ne garder que les prospects en attente filteredList = filteredList.filter { prospect -> prospect.type == "Particulier" } as MutableList<Prospect> recyclerView.adapter = ProspectAdminAdapter(filteredList as MutableList<Prospect>) if(filteredList.size == 0){ Toast.makeText( this@AdminProspects, "Liste vide pour le moment", Toast.LENGTH_SHORT ).show() } }else{ recyclerView.adapter = ProspectAdminAdapter(prospectList) switchPro.isClickable = true } } } override fun onClick(prospect: Prospect) { // Créez une intention pour lancer l'activité AdminProspectsDetails et transmettez les données du prospect val intent = Intent(this, AdminProspectsDetails::class.java) intent.putExtra("email", prospect.email) startActivity(intent) } }
ProspectAdminAdapter类
import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.os.Parcelable import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.TextView import android.widget.Toast import androidx.core.content.ContextCompat.startActivity import androidx.recyclerview.widget.RecyclerView import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.ktx.firestore import com.google.firebase.ktx.Firebase import ml2v.demenagement.all.android.data.model.CardClickListener import ml2v.demenagement.all.android.data.model.PROSPECT_ID_EXTRA import ml2v.demenagement.all.android.data.model.Prospect import ml2v.demenagement.all.android.ui.interfaces.AdminProspectsDetails import ml2v.demenagement.app.android.R import java.io.Serializable class ProspectAdminAdapter(private val prospectList: MutableList<Prospect>) : RecyclerView.Adapter<ProspectAdminAdapter.ProspectAdminViewHolder>() { private var cardClickListener: CardClickListener? = null inner class ProspectAdminViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val textProspectName: TextView = itemView.findViewById(R.id.name_card) val textEmail: TextView = itemView.findViewById(R.id.email_card) val textPhone: TextView = itemView.findViewById(R.id.phone_card) val textMove: TextView = itemView.findViewById(R.id.move_card) val textStatus: TextView = itemView.findViewById(R.id.status_card) val buttonSendRequest: ImageButton = itemView.findViewById(R.id.send_request_card) init { itemView.setOnClickListener { val position = adapterPosition if (position != RecyclerView.NO_POSITION) { val prospect = prospectList[position] cardClickListener?.onClick(prospect) } } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProspectAdminViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.cardview_prospects, parent, false) return ProspectAdminViewHolder(view) } @SuppressLint("SuspiciousIndentation") override fun onBindViewHolder(holder: ProspectAdminViewHolder, position: Int) { val prospect = prospectList[position] holder.textEmail.text = "Adresse email : "+prospect.email holder.textProspectName.text = "Nom du prospect : "+prospect.nom holder.textPhone.text = "Téléphone : "+prospect.tel holder.textMove.text = "Type de prestation : "+prospect.type holder.textStatus.text = "Statut de la prestation : "+prospect.status holder.buttonSendRequest.setOnClickListener { val currentUser = FirebaseAuth.getInstance() val db = Firebase.firestore val userId = currentUser.uid val prospectsCollection = db.collection("demenagement") prospectsCollection.whereEqualTo("mail", prospect.email).get().addOnSuccessListener { querySnapshot -> for (document in querySnapshot.documents) { val documentRef = prospectsCollection.document(document.id) documentRef.delete().addOnSuccessListener { // Suppression réussie val currentPosition = holder.bindingAdapterPosition prospectList.removeAt(currentPosition) notifyItemRemoved(currentPosition) }.addOnFailureListener { e -> Log.d("TAG", "Message de débogage"+e) } } } } } override fun getItemCount(): Int { return prospectList.size } fun setCardClickListener(listener: CardClickListener) { cardClickListener = listener } }
Prospect数据类
package ml2v.demenagement.all.android.data.model var ProspectList = mutableListOf<Prospect>() val PROSPECT_ID_EXTRA = "ProspectExtra" data class Prospect( val categorie: String, var email: String, var nom: String, var siret: String, var tel: String, var type: String, var user: String, var status: String )
CardClickListener接口
package ml2v.demenagement.all.android.data.model interface CardClickListener{ fun onClick(prospect: Prospect) }
AdminProspectsDetails类
package ml2v.demenagement.all.android.ui.interfaces import android.os.Bundle import androidx.activity.ComponentActivity import ml2v.demenagement.all.android.data.model.Prospect import ml2v.demenagement.app.android.R class AdminProspectsDetails:ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_admin_prospect_details) actionBar?.hide() } }
问题分析与修复方案
核心问题
点击无响应的根本原因是:每次数据加载或筛选时,都重新创建了ProspectAdminAdapter实例,但没有绑定点击监听器。初始创建的Adapter虽然设置了setCardClickListener(this),但后续被无监听器的新Adapter覆盖,导致卡片点击事件无法触发。
修复步骤
- 全局保存Adapter实例:避免重复创建Adapter,仅更新数据源
- 数据源变化时刷新UI:调用Adapter的
notifyDataSetChanged()更新,而非重新创建Adapter - 确保所有Adapter实例都绑定监听器:如果必须创建新Adapter,一定要调用
setCardClickListener(this)
关键修改代码
修改AdminProspects类的核心逻辑
class AdminProspects() : ComponentActivity(), CardClickListener { private lateinit var recyclerView: RecyclerView private val prospectList = mutableListOf<Prospect>() private var filteredList = mutableListOf<Prospect>() // 全局保存Adapter实例 private lateinit var adapter: ProspectAdminAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_admin_prospects) actionBar?.hide() recyclerView = findViewById<RecyclerView>(R.id.prospects_views) // 初始化Adapter并绑定监听器 adapter = ProspectAdminAdapter(prospectList) adapter.setCardClickListener(this) recyclerView.adapter = adapter recyclerView.itemAnimator = SlideInUpAnimator() // ... 开关定义部分保留 ... // BDD数据加载部分修改 val db = Firebase.firestore val prospectsCollection = db.collection("demenagement") prospectsCollection.get().addOnSuccessListener { documents -> for (document in documents) { val prospect = document.data val categorie = prospect["categorie"] as String val email = prospect["mail"] as String val nom = prospect["nom"] as String val siret = prospect["siret"] as String val tel = prospect["tel"] as String val type = prospect["type"] as String val status = prospect["status"] as String val usersuid = prospect["users"] as String val usersCollection = db.collection("users") usersCollection.document(usersuid).get().addOnSuccessListener { userDoc -> val userName = userDoc.getString("nom").toString() val newProspect = Prospect(categorie, email, nom, siret, tel, type, userName, status) prospectList.add(newProspect) // 仅刷新UI,不重建Adapter adapter.notifyDataSetChanged() } } } // 开关筛选逻辑修改示例(其他开关同理) switchWaiting.setOnCheckedChangeListener { _, isChecked -> isWaitingSelected = isChecked switchInProgress.isClickable = false switchValidate.isClickable = false if (isChecked) { filteredList = prospectList.filter { it.status == "En attente" } as MutableList<Prospect> // 创建新Adapter时必须绑定监听器 adapter = ProspectAdminAdapter(filteredList) adapter.setCardClickListener(this) recyclerView.adapter = adapter if(filteredList.isEmpty()){ Toast.makeText(this, "Liste vide pour le moment", Toast.LENGTH_SHORT).show() } } else { // 恢复原列表时同样绑定监听器 adapter = ProspectAdminAdapter(prospectList) adapter.setCardClickListener(this) recyclerView.adapter = adapter switchInProgress.isClickable = true switchValidate.isClickable = true } } // ... 其他开关逻辑按上述方式修改 ... } override fun onClick(prospect: Prospect) { val intent = Intent(this, AdminProspectsDetails::class.java) intent.putExtra("email", prospect.email) startActivity(intent) } }
更优方案:给Adapter添加更新数据源方法
在ProspectAdminAdapter中添加以下方法,避免重复创建Adapter实例:
fun updateData(newList: MutableList<Prospect>) { prospectList.clear() prospectList.addAll(newList) notifyDataSetChanged() }
之后在筛选逻辑中只需调用:
adapter.updateData(filteredList)
无需重新创建Adapter,效率更高且不会丢失监听器绑定。
内容的提问来源于stack exchange,提问作者Layer8
相关产品推荐
相关产品推荐

