我如何为 RecyclerView 适配器创建一个包装器,它将接受任何实现 RecyclerView.Adapter<RecyclerView.ViewHolder> 的适配器

How can I create a wrapper for the RecyclerView Adapter that will accept any Adapter that implements RecyclerView.Adapter<RecyclerView.ViewHolder>

我知道标题有点奇怪,抱歉。这是一个奇怪的问题,我什至不确定我能否正确解释它,这是我的尝试:

基本上我想为任何扩展 RecyclerView.Adapter<RecyclerView.ViewHolder> 的适配器实现一个包装器,如果需要,包装器最终将能够插入行,并且它会根据需要修改 getItemCount() 之类的东西,但我离那个部分还很远。

这是我的class定义:

class MyRecyclerAdapterWrapper(activity: Activity,val originalAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

我将要包装的原始适配器传递给它。

如果我有这样的 class 定义,然后我尝试创建一个 MyRecyclerAdapterWrapper 的实例,如下所示:

val wrapper = MyRecyclerAdapterWrapper(activity, myOriginalAdapter)

其中 myOriginalAdapter 是以下的实例:

class MyOriginalAdapter() : RecyclerView.Adapter<MyOriginalAdapter.MyViewHolder>() {

然后我收到一条错误消息,说它期待 RecyclerView.Adapter<RecyclerView.ViewHolder> 但得到的却是 MyOriginalAdapter.

然后我在 class 定义中尝试了 out 关键字,如下所示:

class MyRecyclerAdapterWrapper(activity: Activity,val originalAdapter: RecyclerView.Adapter<out RecyclerView.ViewHolder>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

这允许我的构造函数调用 MyRecyclerAdapterWrapper(activity, myOriginalAdapter) 停止抱怨,但是我的 MyRecyclerAdapterWrapper class 无法实现某些 RecyclerView.Adapter<RecyclerView.ViewHolder> 覆盖,因为 originalAdapter 期望 Nothing 而不是 RecyclerView.ViewHolder.

比如里面MyRecyclerAdapterWrapper我有这段代码:

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        originalAdapter.onBindViewHolder(holder,position)
}

这里的错误是Type mismatchRequired: NothingFound: RecyclerView.ViewHolder.

那么正确的处理方法是什么?

编辑:只是想清楚其他适配器也将使用此包装器,因此包装器必须是通用的。

编辑:我应该提到这一点,有一个类似的包装器可以正常使用,但它在 Java 中,那个包装器的 class 定义是:

public final class MyRecyclerAdapterWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
     public MyRecyclerAdapterWrapper(@NonNull Activity activity,
        @NonNull RecyclerView.Adapter originalAdapter){

编辑:根据@muetzenflo 的回答,我能够使大部分内容正常工作,但某些方法仍然存在问题。

我现在有这个:

class MyRecyclerAdapterWrapper<T : RecyclerView.ViewHolder>(activity: Activity, val originalAdapter: RecyclerView.Adapter<T>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

 class MyCustomAdapter(): RecyclerView.Adapter<MyCustomAdapter.MyViewHolder>(){
        class MyViewHolder(v: View): RecyclerView.ViewHolder(v) {

        }

这个有效:

val myRecyclerAdapterWrapper = MyRecyclerAdapterWrapper(this, MyCustomAdapter())

但这不是:

genericMethod(myRecyclerAdapterWrapper)

private fun genericMethod(myRecyclerAdapterWrapper: MyRecyclerAdapterWrapper<RecyclerView.ViewHolder>) {

    }

错误是:

Type mismatch: inferred type is MainActivity.MyRecyclerAdapterWrapper<MainActivity.MyCustomAdapter.MyViewHolder> but MainActivity.MyRecyclerAdapterWrapper<RecyclerView.ViewHolder> was expected

编辑:我觉得我想出了如何制作通用方法:

private fun <T> genericMethod(myRecyclerAdapterWrapper: MyRecyclerAdapterWrapper<T> ) where T : RecyclerView.ViewHolder {

    }

所以最后这就是我的 class 最终编译和运行的方式:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val myRecyclerAdapterWrapper = MyRecyclerAdapterWrapper(this, MyCustomAdapter())
        genericMethod(myRecyclerAdapterWrapper)
    }
    private fun <T> genericMethod(myRecyclerAdapterWrapper: MyRecyclerAdapterWrapper<T> ) where T : RecyclerView.ViewHolder {
    }
    class MyRecyclerAdapterWrapper<T : RecyclerView.ViewHolder>(activity: Activity, val originalAdapter: RecyclerView.Adapter<T>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return originalAdapter.onCreateViewHolder(parent,viewType)
        }
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            originalAdapter.onBindViewHolder(holder as T,position)
        }
        override fun getItemCount(): Int {
            return originalAdapter.itemCount
        }
    }
    class MyCustomAdapter(): RecyclerView.Adapter<MyCustomAdapter.MyViewHolder>(){
        class MyViewHolder(v: View): RecyclerView.ViewHolder(v) {
        }
        override fun getItemCount(): Int {
            TODO("Not yet implemented")
        }
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            TODO("Not yet implemented")
        }
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            TODO("Not yet implemented")
        }
    }
}

参数需要 Nothing 因为您为通用参数声明了 out

尝试将 RecyclerView.ViewHolder 更改为 MyOriginalAdapter.MyViewHolder


class MyRecyclerAdapterWrapper(activity: Activity,val originalAdapter: RecyclerView.Adapter<MyOriginalAdapter.MyViewHolder>) : RecyclerView.Adapter<MyOriginalAdapter.MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyOriginalAdapter.MyViewHolder {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: MyOriginalAdapter.MyViewHolder, position: Int) {
        originalAdapter.onBindViewHolder(holder, position)
    }

    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }
}

如果我明白你想做什么,这应该可以解决你的一般问题。

您的 RecyclerViewWrapper 可以为 AdapterViewHolder

使用通用类型
class RecyclerViewWrapper<VH : RecyclerView.ViewHolder, A : RecyclerView.Adapter<VH>>(
    activity: Activity,
    val originalAdapter: A
) : RecyclerView.Adapter<VH>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: VH, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }
}

您的 OriginalAdapter 可以是您想要的任何适配器

class OriginalAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }
}

然后要使用它,您可以直接启动它

fun example(activity: Activity) {
    val wrapper = RecyclerViewWrapper(activity, OriginalAdapter())
}

我认为这将能够帮助你(只要我理解正确),你可能需要做一些小的改变来满足你的需要,但不会破坏

我在所有项目中都使用了 2 类 来在 RecyclerView 项目中广泛使用数据绑定:

用法

import androidx.recyclerview.widget.DiffUtil
import de.bvb09.android.R
import de.bvb09.android.data.model.news.NewsComponent
import de.bvb09.android.recyclerview.DataBindingAdapter
import de.bvb09.android.recyclerview.DataBindingViewHolder

/**
 * This adapter is responsible for the optional horizontal image gallery
 */
class ZoomImageAdapter : DataBindingAdapter<String>(DiffCallback) {

    override fun getItemViewType(position: Int): Int {
        return R.layout.item_zoom_image
    }

    /**
     * The DiffCallback is used by the [DataBindingAdapter] to check which items are
     * completely new and which just changed its content. When defining the Boolean checks, be
     * as precise as possible to avoid strange behaviour of the RecyclerView items.
     */
    object DiffCallback : DiffUtil.ItemCallback<String>() {
        override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
            return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
            return oldItem == newItem
        }
    }
}

ListAdapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter

/**
 * This generic Adapter can be used to use any data class T as data provider for recyclerView list items.
 * To send a list of items to this adapter, use the submitList(newList) method. The DiffCallback is then called to
 * detect which items are completely new or have changed content. Animations are created accordingly and automatically.
 */
abstract class DataBindingAdapter<T>(diffCallback: DiffUtil.ItemCallback<T>) : ListAdapter<T, DataBindingViewHolder<T>>(diffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder<T> {
        val layoutInflater = LayoutInflater.from(parent.context)
        val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, viewType, parent, false)
        return DataBindingViewHolder(binding)
    }

    override fun onBindViewHolder(holder: DataBindingViewHolder<T>, position: Int) {
        val item = getItem(position)
        holder.bind(item)
    }
}

ViewHolder

import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import your.package.name.BR

/**
 * This ViewHolder is an addition to the [DataBindingAdapter]. From this, it receives a ViewDataBinding which
 * allows us to connect the data class T with the data-bindings defined in the item layout.
 */
class DataBindingViewHolder<T>(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {

    var item: T? = null
        private set

    fun rebind() {
        binding.invalidateAll()
        binding.executePendingBindings()
    }

    fun bind(item: T) {
        this.item = item
        binding.setVariable(BR.item, item)
        binding.executePendingBindings()
    }
}

您可以使用以下包装器 class 的回收器视图适配器,

public class WrapperRecyclerAdapter extends RecyclerView.Adapter {

    private final RecyclerView.Adapter mAdapter;

    public WrapperRecyclerAdapter(RecyclerView.Adapter adapter) {
        super.setHasStableIds(adapter.hasStableIds());
        mAdapter = adapter;
        mAdapter.registerAdapterDataObserver(new ForwardingDataSetObserver());
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return mAdapter.onCreateViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        mAdapter.onBindViewHolder(holder, position);
    }

    @Override
    public int getItemViewType(int position) {
        return mAdapter.getItemViewType(position);
    }

    @Override
    public void onViewRecycled(RecyclerView.ViewHolder holder) {
        mAdapter.onViewRecycled(holder);
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        mAdapter.onViewAttachedToWindow(holder);
    }

    @Override
    public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
        mAdapter.onViewDetachedFromWindow(holder);
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        mAdapter.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        mAdapter.onDetachedFromRecyclerView(recyclerView);
    }

    @Override
    public long getItemId(int position) {
        return mAdapter.getItemId(position);
    }

    @Override
    public int getItemCount() {
        return mAdapter.getItemCount();
    }

    private class ForwardingDataSetObserver extends RecyclerView.AdapterDataObserver {

        @Override public void onChanged() {
            notifyDataSetChanged();
        }

        @Override public void onItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(positionStart, itemCount);
        }

        @Override public void onItemRangeInserted(int positionStart, int itemCount) {
            notifyItemRangeInserted(positionStart, itemCount);
        }

        @Override public void onItemRangeRemoved(int positionStart, int itemCount) {
            notifyItemRangeRemoved(positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
           notifyDataSetChanged(); //TODO
        }
    }

}