Android 如何在适配器类中使用泛型数据绑定?
我试图在适配器类中使用泛型。以下是我尝试过的:Android 如何在适配器类中使用泛型数据绑定?,android,kotlin,generics,google-cloud-firestore,android-databinding,Android,Kotlin,Generics,Google Cloud Firestore,Android Databinding,我试图在适配器类中使用泛型。以下是我尝试过的: class ItemAdapter<I>( options: FirestoreRecyclerOptions<I> ): FirestoreRecyclerAdapter<I, ItemAdapter<I>.ItemViewHolder<I>>(options) { override fun onCreateViewHolder(parent: ViewGroup, vi
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
}
}
}
与:
如何正确使用泛型并解决此问题?谢谢
编辑:
我不需要将特定的类设置为泛型。我需要以某种方式将项
对象强制转换为特定类的对象。我尝试在名为classType:class
的类中添加一个新属性,并使用以下命令强制转换它:
dataBinding.item = item as classType
但是没有任何运气。我也尝试过:
dataBinding.item = item as I
同样没有运气。带有数据绑定的通用适配器类:
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)
}
classbaseadapter(
private val McContext:上下文?,
private-var-list:list?,//泛型list可以接受任何对象
private val layoutId:Int,//项的布局
private val listener:BaseAdapterListener?=null//在视图中回调
):RecyclerView.Adapter(){
重写CreateViewHolder(父级:ViewGroup,viewType:Int):DataBindingViewHolder{
val layoutInflater=layoutInflater.from(mContext)
返回DataBindingViewHolder(DataBindingUtil.inflate(LayoutFlater、layoutId、parent、false))
}
重写getItemCount():Int{
返回列表?大小?:0
}
趣味getItem(位置:Int):S{
名单?让我看看{
if(位置
以下是如何使用此内部片段:
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
}
}
类DemoFragment:Fragment(),BaseAdapter.BaseAdapterListener{
private-var-adapter:BaseAdapter?=null//指定数据,并将其作为参数
私有lateinit变量绑定:FragmentPracticeBinding
覆盖创建视图(
充气机,
容器:视图组?,
savedInstanceState:捆绑?
):查看{
super.onCreateView(充气机、容器、savedInstanceState)
绑定=碎片实践绑定。充气(充气机、容器、假)
返回binding.root;
}
覆盖已创建的视图(视图:视图,保存状态:捆绑?){
adapter=BaseAdapter(context,arrayListOf(),R.layout.item\u audio,this)//使用特定信息创建了适配器的对象
binding.notesRecyclerView.adapter=适配器
}
覆盖onBind(保持架:BaseAdapter.DataBindingViewHolder,位置:Int){
(holder.binding为ItemAudioBinding)。应用{
//玩你的项目布局
}
//这只不过是item_布局类型的onBindViewHolder
}
}
错误提示,您需要将项目强制转换为键入item
,而不是I
。这是有意义的,因为您的布局使用类型Item
声明变量。但是,ViewHolder提供了一个无约束类型的对象I
,它显然不符合项
您可以将泛型类型I
约束为项的子类型,而不是强制转换:
class ItemAdapter<I: Item>(...) {
...
inner class ItemViewHolder<I: Item>(...) {...}
}
这回答了你的问题吗@ADM No,因为我没有试图使项
类通用,所以我需要以某种方式使布局文件中的项对象通用。该项可以成为产品
对象、用户
对象等等。那么您的变量类型应该是项而不是项的父类型。@ADM我不明白您在上一条评论中说的话。@ADM我已经编辑了我的问题。感谢您的回答,但不幸的是,此解决方案根本没有涉及我的问题。如何将该项
对象强制转换为I
类型的对象?在我的示例中,如果看到baseAdapter,您可以传递任何种类的项对象和任何种类的项布局。内部OnBind(..){holder.binding}
是泛型类型,我在这里显式转换到我的项目--->holder.binding as ItemAudioBinding
它转换到我在创建BaseAdapter时通过的布局我正在扩展FirestoreRecyclerAdapter
,需要根据我在适配器中使用的类型进行转换。嗨,aax!我很抱歉这么晚才回答。无论如何,谢谢你花时间回答我的问题,你是唯一一个明白我在寻找什么的人。然而,使用I:Item
并不能解决我的问题,这是因为我只需要ItemAdapter
,因为I
应该变成Item
,在另一个类中应该变成产品
,依此类推。关于你答案的第二部分,是的,我确实可以使用外部班级的I
。你对我如何解决这个问题还有什么想法吗?投票通过了,我明白了。我在代码中没有得到的东西:“充气”方法从何而来,您在何处定义要使用的布局文件?可能有效的方法是像我在示例中所做的那样,使用非类型化的setVariable
方法设置绑定变量。您只需在所有布局文件中一致地命名变量(例如,模型
而不是项目
/产品
/…).*我已直接导入了它导入com.example.my_app.databinding.ItemDataBinding.flate
。在我的XML文件中添加这个
就足以知道哪个布局被夸大了。让我尝试使用binding.setVariable(BR.model,model)
,如您在回答中所解释的,我会回复您。
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)
}
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
}
}
class ItemAdapter<I: Item>(...) {
...
inner class ItemViewHolder<I: Item>(...) {...}
}
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()
}
}
}