在适配器(ListAdapter)中有 2 个模型 class(dataClass)
Having 2 model class(dataClass) in adapter(ListAdapter)
最近遇到一个比较难解决的问题
我需要在列表适配器中放入 2 个模型,但它总是说需要 2 种类型的参数
Here is the Link of the whole project
我想在 ListAdapter 中使用交易和银行模型
你可以阅读项目README。
我想要2个型号的适配器在ui.TransactionHistory
这是我的整个适配器 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)
}
每当我在这里放置第二个模型时:
ListAdapter<Transaction, **Bank**, RecyclerView.ViewHolder>(BillDiffCallback()) {}
它说需要 2 个类型的参数。
我不知道它是否对你有帮助,但有人告诉我我必须在 Kotlin 中使用 join
感谢您的回答:)
您可以仅基于单个数据源构建列表。如果你想有多个数据源,你应该创建第三个数据模型并在其中添加其他两个模型。
data class ListData(val transaction : Transaction , val Bank : Bank)
ListView/Recycler 视图将根据传递的对象列表创建列表项的数量。
ListAdapter<ListData, RecyclerView.ViewHolder>
ListAdaper 只能接受一个数据模型,但是您可以使用另一个 class 添加多个项目,例如 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
}
}
并仅在您的 ListAdapter 中处理此问题 class 您的代码需要应用此更改
class TransactionHistory() :
ListAdapter<DataItem, RecyclerView.ViewHolder>(BillDiffCallback()) {
private val ITEM_VIEW_TYPE_EMPTY = 0
private val ITEM_VIEW_TYPE_ITEM_TRANSACTION = 1
private val ITEM_VIEW_TYPE_ITEM_BANK = 2
private val adapterScope = CoroutineScope(Dispatchers.Default)
/**
* DO NOT USE .submit(), use the method bellow
*/
fun addTransactionsAndBanks(transactionList: List<Transaction>?, bankList: List<Bank>?) {
adapterScope.launch {
val transactionItems: List<DataItem> = when {
transactionList == null || transactionList.isEmpty() -> listOf(DataItem.Empty)
else -> transactionList.map { DataItem.TransactionItem(it) }
}
val bankItems: List<DataItem> = when {
bankList == null || bankList.isEmpty() -> listOf(DataItem.Empty)
else -> bankList.map { DataItem.BankItem(it) }
}
val items = transactionItems + bankItems
withContext(Dispatchers.Main) {
submitList(items)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_ITEM_TRANSACTION -> ViewHolder.from(parent)
ITEM_VIEW_TYPE_ITEM_BANK -> 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 -> {
when (val item = getItem(position)) {
is DataItem.TransactionItem -> holder.bind(item.transaction, clickListener)
is DataItem.BankItem -> holder.bind2(item.bank, clickListener)
}
}
is EmptyViewHolder -> holder.bind()
}
}
lateinit var clickListener: AdapterListener2
fun setOnclickListener(listener: AdapterListener2) {
clickListener = listener
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.Empty -> ITEM_VIEW_TYPE_EMPTY
is DataItem.TransactionItem -> ITEM_VIEW_TYPE_ITEM_TRANSACTION
is DataItem.BankItem -> ITEM_VIEW_TYPE_ITEM_BANK
}
}
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<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
}
}
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)
}
sealed class DataItem {
abstract val id: Long
data class TransactionItem(val transaction: Transaction) : DataItem() {
override val id = transaction.transId
}
data class BankItem(val bank: Bank) : DataItem() {
override val id = bank.bankId
}
object Empty : DataItem() {
override val id = Long.MIN_VALUE
}
}
我找到了问题的答案
我们必须在查询中使用 Join:
//for single info
@Query("SELECT `transaction`.increase, `transaction`.decrease, bank.bank_name From `transaction` JOIN bank WHERE `transaction`.bank_id=:key ")
fun joinTables(key: Long): LiveData<TransactionAndBank>?
//for list of info
@Query("SELECT `transaction`.increase, `transaction`.decrease,`transaction`.type, bank.bank_name From `transaction` JOIN bank WHERE `transaction`.bank_id=:key ")
fun joinAllTables(key: Long): LiveData<List<TransactionAndBank>>
我不得不把它放在 TransactionDAO 中
source
最近遇到一个比较难解决的问题
我需要在列表适配器中放入 2 个模型,但它总是说需要 2 种类型的参数
Here is the Link of the whole project
我想在 ListAdapter 中使用交易和银行模型
你可以阅读项目README。 我想要2个型号的适配器在ui.TransactionHistory
这是我的整个适配器 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)
}
每当我在这里放置第二个模型时:
ListAdapter<Transaction, **Bank**, RecyclerView.ViewHolder>(BillDiffCallback()) {}
它说需要 2 个类型的参数。
我不知道它是否对你有帮助,但有人告诉我我必须在 Kotlin 中使用 join
感谢您的回答:)
您可以仅基于单个数据源构建列表。如果你想有多个数据源,你应该创建第三个数据模型并在其中添加其他两个模型。
data class ListData(val transaction : Transaction , val Bank : Bank)
ListView/Recycler 视图将根据传递的对象列表创建列表项的数量。
ListAdapter<ListData, RecyclerView.ViewHolder>
ListAdaper 只能接受一个数据模型,但是您可以使用另一个 class 添加多个项目,例如 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
}
}
并仅在您的 ListAdapter 中处理此问题 class 您的代码需要应用此更改
class TransactionHistory() :
ListAdapter<DataItem, RecyclerView.ViewHolder>(BillDiffCallback()) {
private val ITEM_VIEW_TYPE_EMPTY = 0
private val ITEM_VIEW_TYPE_ITEM_TRANSACTION = 1
private val ITEM_VIEW_TYPE_ITEM_BANK = 2
private val adapterScope = CoroutineScope(Dispatchers.Default)
/**
* DO NOT USE .submit(), use the method bellow
*/
fun addTransactionsAndBanks(transactionList: List<Transaction>?, bankList: List<Bank>?) {
adapterScope.launch {
val transactionItems: List<DataItem> = when {
transactionList == null || transactionList.isEmpty() -> listOf(DataItem.Empty)
else -> transactionList.map { DataItem.TransactionItem(it) }
}
val bankItems: List<DataItem> = when {
bankList == null || bankList.isEmpty() -> listOf(DataItem.Empty)
else -> bankList.map { DataItem.BankItem(it) }
}
val items = transactionItems + bankItems
withContext(Dispatchers.Main) {
submitList(items)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_ITEM_TRANSACTION -> ViewHolder.from(parent)
ITEM_VIEW_TYPE_ITEM_BANK -> 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 -> {
when (val item = getItem(position)) {
is DataItem.TransactionItem -> holder.bind(item.transaction, clickListener)
is DataItem.BankItem -> holder.bind2(item.bank, clickListener)
}
}
is EmptyViewHolder -> holder.bind()
}
}
lateinit var clickListener: AdapterListener2
fun setOnclickListener(listener: AdapterListener2) {
clickListener = listener
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.Empty -> ITEM_VIEW_TYPE_EMPTY
is DataItem.TransactionItem -> ITEM_VIEW_TYPE_ITEM_TRANSACTION
is DataItem.BankItem -> ITEM_VIEW_TYPE_ITEM_BANK
}
}
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<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
}
}
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)
}
sealed class DataItem {
abstract val id: Long
data class TransactionItem(val transaction: Transaction) : DataItem() {
override val id = transaction.transId
}
data class BankItem(val bank: Bank) : DataItem() {
override val id = bank.bankId
}
object Empty : DataItem() {
override val id = Long.MIN_VALUE
}
}
我找到了问题的答案
我们必须在查询中使用 Join:
//for single info
@Query("SELECT `transaction`.increase, `transaction`.decrease, bank.bank_name From `transaction` JOIN bank WHERE `transaction`.bank_id=:key ")
fun joinTables(key: Long): LiveData<TransactionAndBank>?
//for list of info
@Query("SELECT `transaction`.increase, `transaction`.decrease,`transaction`.type, bank.bank_name From `transaction` JOIN bank WHERE `transaction`.bank_id=:key ")
fun joinAllTables(key: Long): LiveData<List<TransactionAndBank>>
我不得不把它放在 TransactionDAO 中
source