Recently, I faced with a issue that is a bit hard for me to solve
I need to put 2 models in List adapter, but it always says 2 type arguments expected
here is my whole adapter class:
class TransactionHistory() :
ListAdapter<Transaction, RecyclerView.ViewHolder>(BillDiffCallback()) {
private val ITEM_VIEW_TYPE_EMPTY = 0
private val ITEM_VIEW_TYPE_ITEM = 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_ITEM -> ViewHolder.from(parent)
ITEM_VIEW_TYPE_EMPTY -> EmptyViewHolder.from(parent)
else -> throw ClassCastException("Unknown viewType $viewType")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewHolder -> {
val item = getItem(position)
holder.bind(item, clickListener)
// holder.bind2(Bank, clickListener)
}
is EmptyViewHolder -> {
holder.bind()
}
}
}
lateinit var clickListener: AdapterListener2
fun setOnclickListener(listener: AdapterListener2) {
clickListener = listener
}
override fun getItemViewType(position: Int): Int {
return if (itemCount > 0)
ITEM_VIEW_TYPE_ITEM
else
ITEM_VIEW_TYPE_EMPTY
}
class ViewHolder
private constructor(val binding: ItemUserTransactionListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Transaction, adapterListener2: AdapterListener2) {
binding.transaction = item
binding.clickListener = adapterListener2
binding.executePendingBindings()
if (item.type == "payPayment") {
binding.transactionStatus.text = "برداخت قسط"
} else if (item.type == "decrease") {
binding.transactionStatus.text = "برداشت"
} else if (item.type == "increase") {
binding.transactionStatus.text = "واریز"
}
if (item.decrease == null) {
binding.amount.text = item.increase
} else {
binding.amount.text = item.decrease
}
}
fun bind2(item2: Bank, adapterListener2: AdapterListener2) {
binding.bankInfo = item2
binding.clickListener = adapterListener2
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemUserTransactionListBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding)
}
}
}
}
class EmptyViewHolder private constructor(val binding: ItemUserTransactionListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind() {
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): EmptyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemUserTransactionListBinding.inflate(layoutInflater, parent, false)
return EmptyViewHolder(binding)
}
}
}
class BillDiffCallback : DiffUtil.ItemCallback<Transaction>() {
override fun areItemsTheSame(oldItem: Transaction, newItem: Transaction): Boolean {
return oldItem.transId == newItem.transId
}
override fun areContentsTheSame(
oldItem: Transaction,
newItem: Transaction
): Boolean {
return oldItem == newItem
}
}
class AdapterListener2(
val clickListener: (id: Long?) -> Unit,
val deleteListener: (category: Transaction) -> Unit
) {
fun onclick(transaction: Transaction) = clickListener(transaction.userId)
fun onDeleteClick(userInfo: Transaction) = deleteListener(userInfo)
}
whenever i placed secound model here:
ListAdapter<Transaction, **Bank**, RecyclerView.ViewHolder>(BillDiffCallback()) {}
it says 2 type argument expected.
I don't know if it helps you or not but some one told me I have to use join in Kotlin
THANKS FOR YOUR ANSWERS :)
CodePudding user response:
You can build the list based on only a single data source. If you want to have multiple data sources, you should create a third data model and add the other two models in it.
data class ListData(val transaction : Transaction , val Bank : Bank)
ListView/Recycler view will create number of list items based on the list of objects passed.
ListAdapter<ListData, RecyclerView.ViewHolder>
CodePudding user response:
ListAdaper can only accept one data model however you can add multiple items using another class like Sealed Class
sealed class DataItem {
abstract val id: Long
data class TransactionItem(val transaction: Transaction): DataItem() {
override val id = transaction.transId
}
object Empty: DataItem() {
override val id = Long.MIN_VALUE
}
}
and deal with this only class in your ListAdapter for your code you will need to apply this changes
class TransactionHistory() :
ListAdapter<DataItem, RecyclerView.ViewHolder>(BillDiffCallback()) {
private val ITEM_VIEW_TYPE_EMPTY = 0
private val ITEM_VIEW_TYPE_ITEM = 1
private val adapterScope = CoroutineScope(Dispatchers.Default)
fun addTransactions(list: List<Transaction>?) {
adapterScope.launch {
val items: List<DataItem> = when {
list == null || list.isEmpty() -> listOf(DataItem.Empty)
else -> list.map { DataItem.TransactionItem(it) }
}
withContext(Dispatchers.Main) {
submitList(items)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewHolder -> {
val item = getItem(position) as DataItem.TransactionItem
holder.bind(item, clickListener)
}
is EmptyViewHolder -> holder.bind()
}
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.Empty -> ITEM_VIEW_TYPE_EMPTY
is DataItem.TransactionItem -> ITEM_VIEW_TYPE_ITEM
}
}
}
class BillDiffCallback : DiffUtil.ItemCallback<DataItem>() {
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem == newItem
}
}
sealed class DataItem {
abstract val id: Long
data class TransactionItem(val transaction: Transaction): DataItem() {
override val id = transaction.transId
}
object Empty: DataItem() {
override val id = Long.MIN_VALUE
}
}