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

安卓开发:RecyclerView适配不同属性数据,单Adapter还是多Adapter?

单个Adapter完全能适配不同分类的数据!

绝对可以用单个RecyclerView Adapter搞定所有分类的展示需求,这是Android开发中处理多类型列表的经典场景,完全没必要为每个分类单独编写Adapter——既冗余又增加后续维护成本。下面给你两种可行的实现思路,你可以根据自己的代码结构选择:

思路1:用密封类定义类型安全的数据模型(推荐)

这种方式类型更安全,代码可读性和可维护性更高,适合长期迭代的项目。

首先,创建一个密封类DataItem,然后为每个分类定义对应的子类,把该分类的字段明确写出来:

sealed class DataItem {
    // 姓名分类的数据类
    data class NameItem(val forename: String, val surname: String) : DataItem()
    // 宝藏分类的数据类
    data class TreasureItem(val style: String, val item: String, val value: String) : DataItem()
    // 商店分类的数据类
    data class ShopItem(val name: String, val descriptor: String, val type: String, val quality: String) : DataItem()
}

接下来编写通用Adapter,通过重写getItemViewType来区分不同分类的布局,然后在onCreateViewHolder和onBindViewHolder中分别处理:

class UniversalDataAdapter(private val dataList: List<DataItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        private const val VIEW_TYPE_NAME = 0
        private const val VIEW_TYPE_TREASURE = 1
        private const val VIEW_TYPE_SHOP = 2
    }

    override fun getItemViewType(position: Int): Int {
        return when (dataList[position]) {
            is DataItem.NameItem -> VIEW_TYPE_NAME
            is DataItem.TreasureItem -> VIEW_TYPE_TREASURE
            is DataItem.ShopItem -> VIEW_TYPE_SHOP
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_NAME -> {
                val view = inflater.inflate(R.layout.item_name, parent, false)
                NameViewHolder(view)
            }
            VIEW_TYPE_TREASURE -> {
                val view = inflater.inflate(R.layout.item_treasure, parent, false)
                TreasureViewHolder(view)
            }
            VIEW_TYPE_SHOP -> {
                val view = inflater.inflate(R.layout.item_shop, parent, false)
                ShopViewHolder(view)
            }
            else -> throw IllegalArgumentException("未知的布局类型")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = dataList[position]) {
            is DataItem.NameItem -> (holder as NameViewHolder).bind(item)
            is DataItem.TreasureItem -> (holder as TreasureViewHolder).bind(item)
            is DataItem.ShopItem -> (holder as ShopViewHolder).bind(item)
        }
    }

    override fun getItemCount() = dataList.size

    // 姓名分类的ViewHolder
    class NameViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val tvForename = itemView.findViewById<TextView>(R.id.tv_forename)
        private val tvSurname = itemView.findViewById<TextView>(R.id.tv_surname)

        fun bind(item: DataItem.NameItem) {
            tvForename.text = item.forename
            tvSurname.text = item.surname
        }
    }

    // 宝藏分类的ViewHolder
    class TreasureViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val tvStyle = itemView.findViewById<TextView>(R.id.tv_style)
        private val tvItem = itemView.findViewById<TextView>(R.id.tv_item)
        private val tvValue = itemView.findViewById<TextView>(R.id.tv_value)

        fun bind(item: DataItem.TreasureItem) {
            tvStyle.text = item.style
            tvItem.text = item.item
            tvValue.text = item.value
        }
    }

    // 商店分类的ViewHolder(实现类似)
    class ShopViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        // 初始化控件...
        fun bind(item: DataItem.ShopItem) {
            // 绑定数据...
        }
    }
}

思路2:适配你现有的HashMap结构

如果你想直接复用当前的HashMap数据结构,也可以通过分类标识来区分布局:

首先定义一个通用数据类,包含分类名称和对应的HashMap:

data class GenericDataItem(val category: String, val dataMap: HashMap<String, String>)

然后在Adapter中根据category字段判断布局类型,绑定数据时直接从HashMap中取对应键的值:

class GenericDataAdapter(private val dataList: List<GenericDataItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        private const val VIEW_TYPE_NAME = 0
        private const val VIEW_TYPE_TREASURE = 1
        private const val VIEW_TYPE_SHOP = 2
    }

    override fun getItemViewType(position: Int): Int {
        return when (dataList[position].category) {
            "姓名" -> VIEW_TYPE_NAME
            "宝藏" -> VIEW_TYPE_TREASURE
            "商店" -> VIEW_TYPE_SHOP
            else -> -1
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        // 和思路1类似,根据viewType加载对应布局
        // ...
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val item = dataList[position]
        when (holder.itemViewType) {
            VIEW_TYPE_NAME -> {
                val nameHolder = holder as NameViewHolder
                nameHolder.tvForename.text = item.dataMap["Forename"]
                nameHolder.tvSurname.text = item.dataMap["Surname"]
            }
            VIEW_TYPE_TREASURE -> {
                // 绑定宝藏分类的数据...
            }
            // 其他分类同理
        }
    }

    // ViewHolder实现和思路1类似...
}

总结

两种思路都能实现单个Adapter适配所有分类,推荐思路1,因为密封类的方式类型更安全,后续新增分类只需要新增对应的DataItem子类、布局和ViewHolder,不需要修改Adapter的核心逻辑,扩展性更好。

内容的提问来源于stack exchange,提问作者Black Spike

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:08:21