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

如何在RecyclerView中实现通知列表UI展示及Adapter数据绑定

问题根源

你遇到的报错核心原因如下:

  1. item变量不存在:是因为onBindViewHolder中没有根据索引从数据源中取出对应条目,直接调用了未定义的item变量
  2. 类型不匹配:你的Adapter当前持有NotificationItemsResponse.NotificationItemData(Room实体类)类型的数据源,但ViewHolder的bind方法接收的是NotificationItemUIModel类型参数,两个类型不统一导致报错
  3. 无效代码问题:你在onCreateViewHolder中return之后调用setListData,这行代码永远不会执行,属于无效逻辑

完整修改步骤

1. 新增Room实体转UIModel的转换方法

因为两个数据类字段不匹配,先写扩展方法做类型转换,缺省的UIModel字段你根据自身业务逻辑补全即可:

fun NotificationItemsResponse.NotificationItemData.toUIModel(): NotificationItemUIModel {
    return NotificationItemUIModel(
        id = this.id,
        leadFullName = this.name,
        information = "", // 按需补业务字段值
        product = this.product,
        simpleText = "", // 按需补业务字段值
        data = this.data,
        time = this.time
    )
}

2. 重构NotificationAdapter逻辑

统一用UIModel作为数据源,同时启用DiffUtil做局部刷新替换全局notifyDataSetChanged提升性能:

class NotificationAdapter(
    // 点击事件通过构造函数传入
    private val onItemClicked: (Int) -> Unit,
    diffCallback: DiffUtil.ItemCallback<NotificationItemUIModel> = NotificationUIItemComparator
) : RecyclerView.Adapter<NotificationAdapter.NotificationItemViewHolder>() {

    // 数据源改为UIModel类型,重写set方法自动计算Diff刷新
    var items = emptyList<NotificationItemUIModel>()
        set(value) {
            val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
                override fun getOldListSize() = field.size
                override fun getNewListSize() = value.size
                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                    field[oldItemPosition].id == value[newItemPosition].id
                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                    field[oldItemPosition] == value[newItemPosition]
            })
            field = value
            diffResult.dispatchUpdatesTo(this)
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationItemViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return LayoutListItemNotificationBinding.inflate(inflater, parent, false)
            .let(::NotificationItemViewHolder)
    }

    override fun onBindViewHolder(holder: NotificationItemViewHolder, position: Int) {
        val currentItem = items[position]
        holder.bind(currentItem)
        holder.itemView.setOnClickListener { 
            onItemClicked(currentItem.id) 
        }
    }

    class NotificationItemViewHolder(private val layout: LayoutListItemNotificationBinding) :
        RecyclerView.ViewHolder(layout.root) {
        fun bind(item: NotificationItemUIModel) = with(layout) {
            // 注意字段对应关系,tvName对应UIModel的leadFullName字段
            tvName.text = item.leadFullName
            tvProductNotification.text = item.product
            tvSimpleText.text = item.simpleText
            tvInformation.text = item.information
            tvTime.text = item.time
            tvData.text = item.data
        }
    }

    override fun getItemCount(): Int = items.size

    object NotificationUIItemComparator : DiffUtil.ItemCallback<NotificationItemUIModel>() {
        override fun areItemsTheSame(
            oldItem: NotificationItemUIModel,
            newItem: NotificationItemUIModel
        ) = oldItem.id == newItem.id

        override fun areContentsTheSame(
            oldItem: NotificationItemUIModel,
            newItem: NotificationItemUIModel
        ) = oldItem == newItem
    }
}

3. Fragment中绑定数据并渲染UI

在Flow收集回调中做类型转换,直接赋值给Adapter的items即可自动刷新列表:

// Fragment全局变量初始化Adapter,传入点击事件回调
private val notificationAdapter = NotificationAdapter(
    onItemClicked = { itemId ->
        // 此处写点击item后的业务逻辑,比如跳转详情页
    }
)

// 在onCreateView中给RecyclerView设置Adapter
binding.recyclerView.apply {
    adapter = notificationAdapter
    layoutManager = LinearLayoutManager(requireContext())
}

// 收集ViewModel的StateFlow数据更新UI
vm.test.collectWith(viewLifecycleOwner) { roomDataList ->
    Log.d("TEST", "test message $roomDataList")
    // 把Room实体列表批量转成UIModel列表
    val uiModelList = roomDataList.map { it.toUIModel() }
    // 更新Adapter数据源自动刷新列表
    notificationAdapter.items = uiModelList
}

注意事项

  • NotificationItemUIModel中information、simpleText等Room实体没有的字段,你根据自身业务需求在转换方法中补全对应值即可
  • 原有setListData方法已经不需要,直接给adapter.items赋值就会自动做差分刷新,性能远高于notifyDataSetChanged

内容的提问来源于stack exchange,提问作者chrisu.chrisu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 16:15:04