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

两个RecyclerView复用同一Adapter出现布局加载异常求助

问题分析与解决方案

问题描述

在TabLayout中使用两个Fragment复用同一个RecyclerView Adapter时,出现布局加载异常:第一个Fragment本该显示的内容被跳过,第二个Fragment的内容错误显示在第一个Fragment上,第二个Fragment为空。调试器报错:E/RecyclerView: No adapter attached; skipping layout。

核心问题原因

  • 错误获取View实例:两个Fragment的initView()方法中,使用requireActivity().findViewById(R.id.loanRecRcv)获取RecyclerView,这会拿到Activity中的同一个RecyclerView实例,导致两个Fragment操作的是同一个控件,内容串位。
  • Fragment内部列表未同步:调用loanRecRcvAdapter.setData()后,Fragment自身的list变量没有更新,点击事件中会出现数据不匹配的问题。
  • Adapter泛型缺失:Adapter定义中private var list: List = emptyList()没有指定泛型类型,存在类型安全隐患。

修复后的代码

第一个Fragment(OpenLoansFragment)

private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var loanRecRcv: RecyclerView
private var list: ArrayList<LoanRecordModel> = ArrayList()
private lateinit var loanRecRcvAdapter: LoanRecRcvAdapter // 延迟初始化,避免提前绑定空列表

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = FragmentOpenLoansBinding.inflate(inflater, container, false)
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    initView()
    // 初始化Adapter并绑定数据
    val dataList = listOf(
        LoanRecordModel("", "Petty Cash Loan", "12/05/2022", "Open")
    )
    list.clear()
    list.addAll(dataList)
    loanRecRcvAdapter = LoanRecRcvAdapter(list, this)
    // 配置RecyclerView
    loanRecRcv.apply {
        layoutManager = LinearLayoutManager(activity)
        adapter = loanRecRcvAdapter
    }
}

override fun OnClick(position: Int) {
    Toast.makeText(activity, list[position].loan_type, Toast.LENGTH_SHORT).show()
}

private fun initView() {
    // 使用ViewBinding获取当前Fragment布局内的控件,而非Activity的
    swipeRefreshLayout = binding.swipeRefresh
    loanRecRcv = binding.loanRecRcv
}

第二个Fragment(ClosedLoansFragment)

private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var loanRecRcv: RecyclerView
private var list: ArrayList<LoanRecordModel> = ArrayList()
private lateinit var loanRecRcvAdapter: LoanRecRcvAdapter

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = FragmentClosedLoansBinding.inflate(inflater, container, false)
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    initView()
    // 初始化数据和Adapter
    val dataList = listOf(
        LoanRecordModel("", "Regular Loan", "12/05/2022", "Closed"),
        LoanRecordModel("", "Petty Cash Loan", "05/04/2022", "Closed")
    )
    list.clear()
    list.addAll(dataList)
    loanRecRcvAdapter = LoanRecRcvAdapter(list, this)
    // 配置RecyclerView
    loanRecRcv.apply {
        layoutManager = LinearLayoutManager(activity)
        adapter = loanRecRcvAdapter
    }
}

override fun OnClick(position: Int) {
    Toast.makeText(activity, list[position].loan_type, Toast.LENGTH_SHORT).show()
}

private fun initView() {
    // 使用ViewBinding获取当前Fragment的控件
    swipeRefreshLayout = binding.swipeRefresh
    loanRecRcv = binding.loanRecRcv
}

修复后的Adapter

class LoanRecRcvAdapter(
    private var list: List<LoanRecordModel> = emptyList(), // 补充泛型
    val listener: MyOnClickListener
) : RecyclerView.Adapter<LoanRecRcvAdapter.MyViewHolder>() {

    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val typeTv = itemView.findViewById<TextView>(R.id.loanType)
        val dateTv = itemView.findViewById<TextView>(R.id.dueDate)

        init {
            itemView.setOnClickListener {
                val position = adapterPosition
                if (position != RecyclerView.NO_POSITION) { // 防止无效位置点击
                    listener.OnClick(position)
                }
            }
        }
    }

    fun setData(data: List<LoanRecordModel>) {
        list = data.toList()
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.record_layout, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = list[position]
        holder.apply {
            typeTv.text = item.loan_type
            dateTv.text = item.due_date
        }
    }

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

    interface MyOnClickListener {
        fun OnClick(position: Int)
    }
}

关键修复点说明

  • 控件获取方式:改用ViewBinding的binding.xxx获取当前Fragment布局内的控件,确保每个Fragment操作自己的RecyclerView实例。
  • Adapter初始化时机:延迟到onViewCreated中初始化Adapter,确保数据准备完成后再绑定到RecyclerView,避免空Adapter警告。
  • 数据同步:更新Adapter数据时,同时同步Fragment自身的list变量,保证点击事件数据一致。
  • 泛型与安全优化:补充Adapter列表的泛型类型,添加点击位置有效性判断,提升代码安全性。

内容的提问来源于stack exchange,提问作者Nigel Manimtim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:35:22