如何在适配器 class 中使用泛型数据绑定?
How to use databinding with generics in an adapter class?
我正在尝试在我的适配器中使用泛型 class。这是我尝试过的:
class ItemAdapter<I>(
options: FirestoreRecyclerOptions<I>
): FirestoreRecyclerAdapter<I, ItemAdapter<I>.ItemViewHolder<I>>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder<I> {
val layoutInflater = LayoutInflater.from(parent.context)
val dataBinding = inflate(layoutInflater, parent, false)
return ItemViewHolder(dataBinding)
}
override fun onBindViewHolder(holder: ItemViewHolder<I>, position: Int, item: I) {
holder.bindItem(item)
}
inner class ItemViewHolder<I>(
private val dataBinding: ItemDataBinding
) : RecyclerView.ViewHolder(dataBinding.root) {
fun bindItem(item: I) {
dataBinding.item = item //Here is the problem
}
}
}
这是我的布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="ItemDataBinding">
<variable
name="item"
type="com.example.myapp.Item" />
</data>
<TextView
android:id="@+id/item_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}" />
</layout>
我添加了 item
对象,这样我就可以访问 name
字段。但是,Android Studio 在这一行抱怨:
dataBinding.item = item
有:
Type mismatch.
Required: Item!
Found: I
如何正确使用泛型并解决这个问题?谢谢
编辑:
我不需要使特定的 class 通用。我需要以某种方式将 item
对象转换为特定 class 的对象。我试图在名为 classType: Class<I>
的 class 中添加一个新的 属性 并使用:
dataBinding.item = item as classType
但没有任何运气。我也试过:
dataBinding.item = item as I
再次失败。
具有数据绑定的通用适配器class:
class BaseAdapter<S>(
private val mContext: Context?,
private var list: List<S>?,//generic list can take any Object
private val layoutId: Int,// the item_layout
private val listener: BaseAdapterListener? =null// call back inside your view
) : RecyclerView.Adapter<BaseAdapter.DataBindingViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder {
val layoutInflater = LayoutInflater.from(mContext)
return DataBindingViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false))
}
override fun getItemCount(): Int {
return list?.size ?: 0
}
fun getItem(position: Int):S {
list?.let {
if (position < it.size)
return it[position]
}
return list?.get(position) ?: null as S
}
override fun onBindViewHolder(holder: DataBindingViewHolder, position: Int) {
listener?.onBind(holder, position)
}
interface BaseAdapterListener {
fun onBind(holder: DataBindingViewHolder, position: Int)
}
class DataBindingViewHolder( val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)
}
这是在 Fragment 中使用它的方法:
class DemoFragment : Fragment(),BaseAdapter.BaseAdapterListener {
private var adapter: BaseAdapter<Audio>?= null// specify your data it taking List<Audio> as parameter
private lateinit var binding: FragmentPracticeBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentPracticeBinding.inflate(inflater,container,false)
return binding.root;
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
adapter = BaseAdapter(context, arrayListOf(),R.layout.item_audio,this)//created the object of adapter with specific info
binding.notesRecyclerView.adapter = adapter
}
override fun onBind(holder: BaseAdapter.DataBindingViewHolder, position: Int) {
(holder.binding as ItemAudioBinding).apply {
// play with your item layout
}
// this nothing but your onBindViewHolder of item_layout type
}
}
错误表明,您需要将项目强制转换为类型 Item
而不是 I
。这是有道理的,因为您的布局声明了类型为 Item
的变量。然而,ViewHolder 提供了一个不受约束类型 I
的对象,这显然不符合 Item
.
您可以将泛型 I
约束为 Item
的子类型,而不是强制转换:
class ItemAdapter<I: Item>(...) {
...
inner class ItemViewHolder<I: Item>(...) {...}
}
这应该使分配 dataBinding.item = item
有效。
有点不相关:我认为没有必要为内部 class 重新声明通用类型 I
。您应该可以只使用外部 class ItemAdapter<I: Item>
.
的 I
我不得不承认我并不完全理解您的代码,所以我可能遗漏了一些东西。供您参考,这是我在我的项目中使用的具有数据绑定的适配器的非常相似的实现。它允许可配置的布局。它唯一假设的是一个名为 model
.
的绑定变量
class DataBindingListAdapter<T>(@LayoutRes private val itemLayout: Int, diffCallback: DiffUtil.ItemCallback<T>) : ListAdapter<T, DataBindingListAdapter<T>.ViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, itemLayout, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(model: T?) {
binding.setVariable(BR.model, model)
binding.executePendingBindings()
}
}
}
我正在尝试在我的适配器中使用泛型 class。这是我尝试过的:
class ItemAdapter<I>(
options: FirestoreRecyclerOptions<I>
): FirestoreRecyclerAdapter<I, ItemAdapter<I>.ItemViewHolder<I>>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder<I> {
val layoutInflater = LayoutInflater.from(parent.context)
val dataBinding = inflate(layoutInflater, parent, false)
return ItemViewHolder(dataBinding)
}
override fun onBindViewHolder(holder: ItemViewHolder<I>, position: Int, item: I) {
holder.bindItem(item)
}
inner class ItemViewHolder<I>(
private val dataBinding: ItemDataBinding
) : RecyclerView.ViewHolder(dataBinding.root) {
fun bindItem(item: I) {
dataBinding.item = item //Here is the problem
}
}
}
这是我的布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="ItemDataBinding">
<variable
name="item"
type="com.example.myapp.Item" />
</data>
<TextView
android:id="@+id/item_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}" />
</layout>
我添加了 item
对象,这样我就可以访问 name
字段。但是,Android Studio 在这一行抱怨:
dataBinding.item = item
有:
Type mismatch.
Required: Item!
Found: I
如何正确使用泛型并解决这个问题?谢谢
编辑:
我不需要使特定的 class 通用。我需要以某种方式将 item
对象转换为特定 class 的对象。我试图在名为 classType: Class<I>
的 class 中添加一个新的 属性 并使用:
dataBinding.item = item as classType
但没有任何运气。我也试过:
dataBinding.item = item as I
再次失败。
具有数据绑定的通用适配器class:
class BaseAdapter<S>(
private val mContext: Context?,
private var list: List<S>?,//generic list can take any Object
private val layoutId: Int,// the item_layout
private val listener: BaseAdapterListener? =null// call back inside your view
) : RecyclerView.Adapter<BaseAdapter.DataBindingViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder {
val layoutInflater = LayoutInflater.from(mContext)
return DataBindingViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false))
}
override fun getItemCount(): Int {
return list?.size ?: 0
}
fun getItem(position: Int):S {
list?.let {
if (position < it.size)
return it[position]
}
return list?.get(position) ?: null as S
}
override fun onBindViewHolder(holder: DataBindingViewHolder, position: Int) {
listener?.onBind(holder, position)
}
interface BaseAdapterListener {
fun onBind(holder: DataBindingViewHolder, position: Int)
}
class DataBindingViewHolder( val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)
}
这是在 Fragment 中使用它的方法:
class DemoFragment : Fragment(),BaseAdapter.BaseAdapterListener {
private var adapter: BaseAdapter<Audio>?= null// specify your data it taking List<Audio> as parameter
private lateinit var binding: FragmentPracticeBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentPracticeBinding.inflate(inflater,container,false)
return binding.root;
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
adapter = BaseAdapter(context, arrayListOf(),R.layout.item_audio,this)//created the object of adapter with specific info
binding.notesRecyclerView.adapter = adapter
}
override fun onBind(holder: BaseAdapter.DataBindingViewHolder, position: Int) {
(holder.binding as ItemAudioBinding).apply {
// play with your item layout
}
// this nothing but your onBindViewHolder of item_layout type
}
}
错误表明,您需要将项目强制转换为类型 Item
而不是 I
。这是有道理的,因为您的布局声明了类型为 Item
的变量。然而,ViewHolder 提供了一个不受约束类型 I
的对象,这显然不符合 Item
.
您可以将泛型 I
约束为 Item
的子类型,而不是强制转换:
class ItemAdapter<I: Item>(...) {
...
inner class ItemViewHolder<I: Item>(...) {...}
}
这应该使分配 dataBinding.item = item
有效。
有点不相关:我认为没有必要为内部 class 重新声明通用类型 I
。您应该可以只使用外部 class ItemAdapter<I: Item>
.
I
我不得不承认我并不完全理解您的代码,所以我可能遗漏了一些东西。供您参考,这是我在我的项目中使用的具有数据绑定的适配器的非常相似的实现。它允许可配置的布局。它唯一假设的是一个名为 model
.
class DataBindingListAdapter<T>(@LayoutRes private val itemLayout: Int, diffCallback: DiffUtil.ItemCallback<T>) : ListAdapter<T, DataBindingListAdapter<T>.ViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, itemLayout, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class ViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(model: T?) {
binding.setVariable(BR.model, model)
binding.executePendingBindings()
}
}
}