You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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覆盖,导致卡片点击事件无法触发。

修复步骤

  1. 全局保存Adapter实例:避免重复创建Adapter,仅更新数据源
  2. 数据源变化时刷新UI:调用Adapter的notifyDataSetChanged()更新,而非重新创建Adapter
  3. 确保所有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:47:50