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

Android ListAdapter适配Transaction与Bank两种数据模型时类型参数报错问题咨询

Solution for Adapting Two Models in ListAdapter

First, let's clarify why your initial approach failed: ListAdapter is designed to work with a single data type as its first generic parameter (the definition is ListAdapter<T, VH extends RecyclerView.ViewHolder>), so passing three types like ListAdapter<Transaction, Bank, RecyclerView.ViewHolder> will always throw a "requires 2 type arguments" error.

To handle both Transaction and Bank models in the same adapter, we'll use a sealed class to wrap both types into a unified list item, then adjust the adapter to work with this wrapper. Here's a step-by-step implementation:

Step 1: Create a Sealed Class for Unified List Items

This class will act as a container for both your models, letting the adapter distinguish between them:

sealed class ListItem {
    data class TransactionItem(val transaction: Transaction) : ListItem()
    data class BankItem(val bank: Bank) : ListItem()
}

Step 2: Update the DiffUtil Callback

We need a DiffUtil.ItemCallback that can compare our sealed class items:

class ListItemDiffCallback : DiffUtil.ItemCallback<ListItem>() {
    override fun areItemsTheSame(oldItem: ListItem, newItem: ListItem): Boolean {
        return when {
            oldItem is ListItem.TransactionItem && newItem is ListItem.TransactionItem -> 
                oldItem.transaction.transId == newItem.transaction.transId
            oldItem is ListItem.BankItem && newItem is ListItem.BankItem -> 
                oldItem.bank.id == newItem.bank.id // Replace with Bank's unique identifier
            else -> false
        }
    }

    override fun areContentsTheSame(oldItem: ListItem, newItem: ListItem): Boolean {
        return oldItem == newItem
    }
}

Step 3: Rewrite the Adapter Class

Modify your TransactionHistory adapter to use ListItem as the data type, and add logic to handle both item types:

class TransactionHistory() : ListAdapter<ListItem, RecyclerView.ViewHolder>(ListItemDiffCallback()) {
    private val ITEM_VIEW_TYPE_TRANSACTION = 1
    private val ITEM_VIEW_TYPE_BANK = 2
    private val ITEM_VIEW_TYPE_EMPTY = 0

    override fun getItemViewType(position: Int): Int {
        return if (itemCount == 0) {
            ITEM_VIEW_TYPE_EMPTY
        } else {
            when (getItem(position)) {
                is ListItem.TransactionItem -> ITEM_VIEW_TYPE_TRANSACTION
                is ListItem.BankItem -> ITEM_VIEW_TYPE_BANK
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            ITEM_VIEW_TYPE_TRANSACTION -> TransactionViewHolder.from(parent)
            ITEM_VIEW_TYPE_BANK -> BankViewHolder.from(parent)
            ITEM_VIEW_TYPE_EMPTY -> EmptyViewHolder.from(parent)
            else -> throw ClassCastException("Unknown viewType $viewType")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val item = getItem(position)
        when (holder) {
            is TransactionViewHolder -> {
                val transactionItem = item as ListItem.TransactionItem
                holder.bind(transactionItem.transaction, clickListener)
            }
            is BankViewHolder -> {
                val bankItem = item as ListItem.BankItem
                holder.bind(bankItem.bank, clickListener)
            }
            is EmptyViewHolder -> holder.bind()
        }
    }

    lateinit var clickListener: AdapterListener2

    fun setOnclickListener(listener: AdapterListener2) {
        clickListener = listener
    }

    // Existing Transaction ViewHolder (renamed for clarity)
    class TransactionViewHolder private constructor(val binding: ItemUserTransactionListBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Transaction, adapterListener2: AdapterListener2) {
            binding.transaction = item
            binding.clickListener = adapterListener2
            binding.executePendingBindings()
            
            binding.transactionStatus.text = when(item.type) {
                "payPayment" -> "برداخت قسط"
                "decrease" -> "برداشت"
                "increase" -> "واریز"
                else -> ""
            }
            
            binding.amount.text = item.decrease ?: item.increase
        }

        companion object {
            fun from(parent: ViewGroup): TransactionViewHolder {
                val inflater = LayoutInflater.from(parent.context)
                val binding = ItemUserTransactionListBinding.inflate(inflater, parent, false)
                return TransactionViewHolder(binding)
            }
        }
    }

    // New ViewHolder for Bank items
    class BankViewHolder private constructor(val binding: ItemBankInfoBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Bank, adapterListener2: AdapterListener2) {
            binding.bankInfo = item
            binding.clickListener = adapterListener2
            binding.executePendingBindings()
            // Add any Bank-specific binding logic here
        }

        companion object {
            fun from(parent: ViewGroup): BankViewHolder {
                val inflater = LayoutInflater.from(parent.context)
                val binding = ItemBankInfoBinding.inflate(inflater, parent, false)
                return BankViewHolder(binding)
            }
        }
    }

    // Empty ViewHolder remains unchanged
    class EmptyViewHolder private constructor(val binding: ItemUserTransactionListBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind() {
            binding.executePendingBindings()
        }

        companion object {
            fun from(parent: ViewGroup): EmptyViewHolder {
                val inflater = LayoutInflater.from(parent.context)
                val binding = ItemUserTransactionListBinding.inflate(inflater, parent, false)
                return EmptyViewHolder(binding)
            }
        }
    }
}

Step 4: Combine and Submit Data

To use the adapter, merge your Transaction and Bank lists into a single list of ListItem (this is what the "join operation" suggestion refers to):

// Fetch your data sources
val transactions: List<Transaction> = getTransactions()
val banks: List<Bank> = getBanks()

// Combine into a unified list
val combinedList = transactions.map { ListItem.TransactionItem(it) } + banks.map { ListItem.BankItem(it) }

// Submit to adapter
transactionHistoryAdapter.submitList(combinedList)

Notes:

  • If Transaction and Bank can share the same layout, you can skip creating a separate BankViewHolder and modify the existing TransactionViewHolder to handle both item types, but separate ViewHolders keep your code cleaner.
  • Update AdapterListener2 if you need different click logic for Bank items (e.g., add a bank-specific click handler).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:37:46