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()
        }
    }

}