创建可与任何数据模型一起使用的RecyclerView适配器(

For Android developers (and for mobile developers in general) the most important UI component is List view. We mobile developers just cannot live without Lists (and they are awesome). As awesome they are, sometimes they can become so repetitive and boring to write code for them. As programmers we would like to follow DRY as much as possible, and re use code as much as possible. So I made a simple library that can handle basic List responsibilities for Android. Okay, let’s see the code.

对于Android开发人员(以及一般来说对于移动开发人员),最重要的UI组件是List view 。 我们的移动开发人员无法没有Lists (他们很棒)。 它们真棒,有时可能变得如此重复和无聊,无法为他们编写代码。 作为程序员,我们希望尽可能地遵循DRY ,并尽可能地重用代码。 因此,我做了一个简单的库,可以处理Android的基本List职责。 好的,让我们看一下代码。

public class BaseRecyclerViewAdapter<T extends BaseItemModel>
    extends RecyclerView.Adapter<BaseRecyclerViewHolder<T>> {
    private int resourceId;
    private int variableId;
    private ListItemOnClickListener listItemOnClickListener;
    @NonNull private AsyncListDiffer<T> asyncListDiffer;


    public BaseRecyclerViewAdapter(
        int resourceId,
        int variableId,
        BaseDiffUtilItemCallback<T> baseDiffUtilItemCallback,
        ListItemOnClickListener listItemOnClickListener
    ) {
        this.resourceId = resourceId;
        this.variableId = variableId;
        this.listItemOnClickListener = listItemOnClickListener;
        asyncListDiffer = new AsyncListDiffer<>(this, baseDiffUtilItemCallback);
    }


    @Override
    @NonNull
    public BaseRecyclerViewHolder<T> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new BaseRecyclerViewHolder<>(
            DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                resourceId,
                parent,
                false
            ),
            variableId,
            listItemOnClickListener
        );
    }


    @Override
    public void onBindViewHolder(@NonNull BaseRecyclerViewHolder<T> holder, int position) {
        holder.bind(asyncListDiffer.getCurrentList().get(position));
    }


    @Override
    public int getItemCount() {
        return asyncListDiffer.getCurrentList().size();
    }


    @NonNull
    public List<T> getData() {
        return asyncListDiffer.getCurrentList();
    }


    public void submitList(@NonNull List<T> objList) {
        asyncListDiffer.submitList(objList);
    }
}

Here the important stuffs are these two parameters - int resourceId &int variableId of the constructor. BaseItemModel is a data model class which has an id field (it must have unique values for each object in the list), which is used in DiffUtil.ItemCallback. The model class must inherit from BaseItemModel to use the adapter. A DiffUtil.ItemCallback (named BaseDiffUtilItemCallback) is also provided. You can read about DiffUtil and AsyncListDiffer. They are used to ensure best performance when the list contents are needed to be updated. The code for BaseDiffUtilItemCallback is given below.

这里重要的东西是这两个参数-构造函数的int resourceIdint variableIdBaseItemModel是一个数据模型类,它具有一个id字段(它对于列表中的每个对象都必须具有唯一的值),该字段DiffUtil.ItemCallback中使用 。 模型类必须继承自BaseItemModel才能使用适配器。 还提供了DiffUtil.ItemCallback (名为BaseDiffUtilItemCallback) 。 您可以阅读有关DiffUtilAsyncListDiffer的信息 。 它们用于确保需要更新列表内容时的最佳性能。 下面给出了BaseDiffUtilItemCallback的代码。

public class BaseDiffUtilItemCallback<T extends BaseItemModel> extends DiffUtil.ItemCallback<T> {


    @Override
    public boolean areItemsTheSame(@NonNull T oldItem, @NonNull T newItem) {
        return oldItem.getId().equals(newItem.getId());
    }


    @Override
    public boolean areContentsTheSame(@NonNull T oldItem, @NonNull T newItem) {
        return oldItem.equals(newItem);
    }
}

And the BaseItemModel.

还有BaseItemModel。

public abstract class BaseItemModel {
    @NonNull private String id;


    public BaseItemModel(@NonNull String id) {
        this.id = Objects.requireNonNull(id, "id must not be null");
    }


    @NonNull
    public String getId() {
        return id;
    }


    @Override
    public boolean equals(@Nullable Object obj) {
        if(obj == null) {
            return false;
        }
        // check BaseItemModel is a superclass of obj's Class
        if(!BaseItemModel.class.isAssignableFrom(obj.getClass())) {
            return false;
        }
        return id.equals(((BaseItemModel) obj).getId());
    }
}

Below is the code for the BaseRecyclerViewHolder.

以下是BaseRecyclerViewHolder的代码。

public class BaseRecyclerViewHolder<T> extends RecyclerView.ViewHolder
    implements View.OnClickListener, View.OnLongClickListener {
    private ViewDataBinding viewDataBinding;
    private int variableId;
    private ListItemOnClickListener listItemOnClickListener;


    public BaseRecyclerViewHolder(
        ViewDataBinding viewDataBinding,
        int variableId,
        ListItemOnClickListener listItemOnClickListener
    ) {
        super(viewDataBinding.getRoot());
        this.viewDataBinding = viewDataBinding;
        this.variableId = variableId;
        this.listItemOnClickListener = listItemOnClickListener;
        if(listItemOnClickListener != null) {
            View viewRoot = viewDataBinding.getRoot();
            viewRoot.setOnClickListener(this);
            viewRoot.setOnLongClickListener(this);
        }
    }


    public void bind(T type) {
        viewDataBinding.setVariable(variableId, type);
        viewDataBinding.executePendingBindings();
    }


    @Override
    public void onClick(View view) {
        listItemOnClickListener.onItemClick(getAdapterPosition(), view);
    }


    @Override
    public boolean onLongClick(View view) {
        return listItemOnClickListener.onItemLongClick(getAdapterPosition(), view);
    }
}

The bind method takes the generic type parameter T which is the model type passed to the adapter. viewDataBinding.setVariable(variableId, type) This line passes the object to the xml code (variable id will be passed in BR.<generatedName> form). viewDataBinding.executePendingBindings() will perform the bindings immediately rather than waiting for the next frame. For handling onClick and onLongClick events ListItemOnClickListener is provided.

bind方法采用通用类型参数T,它是传递给适配器的模型类型。 viewDataBinding.setVariable(variableId,type)这行代码将对象传递给xml代码(变量ID将以BR。< GeneratedName >形式传递)。 viewDataBinding.executePendingBindings()将立即执行绑定,而不是等待下一帧。 为了处理onClick和onLongClick事件,提供了ListItemOnClickListener

public interface ListItemOnClickListener {


    void onItemClick(int adapterPosition, View view);


    boolean onItemLongClick(int adapterPosition, View view);
}

I have also supplied a simpler version of the adapter in this library BaseSimpleRecyclerViewAdapter which will work with any data model (no need to extend from BaseItemModel). But of course it uses notifyDataSetChanged() which is not good for performance. So I recommend using the one which uses DiffUtil.ItemCallback.

我还在该库BaseSimpleRecyclerViewAdapter中提供了适配器的简化版本,该版本可与任何数据模型一起使用(无需从BaseItemModel扩展)。 但是当然,它使用notifyDataSetChanged() ,这对性能不利 。 因此,我建议使用一种使用DiffUtil.ItemCallback的方法。

public class BaseSimpleRecyclerViewAdapter<T>
    extends RecyclerView.Adapter<BaseRecyclerViewHolder<T>> {
    private int resourceId;
    private int variableId;
    private ListItemOnClickListener listItemOnClickListener;
    @Nullable private List<T> objList;


    public BaseSimpleRecyclerViewAdapter(
        int resourceId,
        int variableId,
        ListItemOnClickListener listItemOnClickListener
    ) {
        this.resourceId = resourceId;
        this.variableId = variableId;
        this.listItemOnClickListener = listItemOnClickListener;
    }


    @Override
    @NonNull
    public BaseRecyclerViewHolder<T> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new BaseRecyclerViewHolder<>(
            DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                resourceId,
                parent,
                false
            ),
            variableId,
            listItemOnClickListener
        );
    }


    @Override
    public void onBindViewHolder(@NonNull BaseRecyclerViewHolder<T> holder, int position) {
        if(objList != null) {
            holder.bind(objList.get(position));
        }
    }


    @Override
    public int getItemCount() {
        return objList != null ? objList.size() : 0;
    }


    @Nullable
    public List<T> getData() {
        return objList;
    }


    public void submitList(@Nullable List<T> objList) {
        this.objList = objList;
        notifyDataSetChanged();
    }
}

用法: (Usage:)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">


    <data>
        <variable
            name="rowMainListObj"
            type="com.tanveershafeeprottoy.baserecyclerviewadapter.sample.ItemModel" />
    </data>


    <TextView
        android:id="@+id/rowCategoryListTextViewTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackground"
        android:padding="8dp"
        android:text="@{rowMainListObj.name}"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5" />
</layout>
class MainActivity : AppCompatActivity(),
                     ListItemOnClickListener {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val activityMainBinding: ActivityMainBinding = DataBindingUtil.setContentView(
            this,
            R.layout.activity_main
        )
        val itemModelList = mutableListOf<ItemModel>()
        for(i in 0..29) {
            val itemModel = ItemModel(
                itemId = i.toString()
            )
            itemModel.name = i.toString()
            itemModelList.add(itemModel)
        }
        val baseRecyclerViewAdapter = BaseRecyclerViewAdapter<ItemModel>(
            R.layout.row_main_list,
            BR.rowMainListObj,
            BaseDiffUtilItemCallback(),
            this
        )
        activityMainBinding.activityMainRecyclerView.apply {
            setHasFixedSize(true)
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = baseRecyclerViewAdapter
        }
        baseRecyclerViewAdapter.submitList(itemModelList)
    }


    override fun onItemClick(adapterPosition: Int, view: View?) {
        Toast.makeText(
            this,
            "onItemClick $adapterPosition",
            Toast.LENGTH_SHORT
        ).show()
    }


    override fun onItemLongClick(adapterPosition: Int, view: View?): Boolean {
        Toast.makeText(
            this,
            "onItemLongClick $adapterPosition",
            Toast.LENGTH_SHORT
        ).show()
        return true
    }
}

For demo purpose itemModelList is generated. BaseRecyclerViewAdapter is initialised passing R.layout.row_main_list (row layout), BR.rowMainListObj (data binding variable), BaseDiffUtilItemCallback() and this (ListItemOnClickListener implementing class). Finally with baseRecyclerViewAdapter.submitList(itemModelList) the recycler view is populated with data.

出于演示目的,生成了itemModelList。 BaseRecyclerViewAdapter被初始化传递R.layout.row_main_list(行布局),BR.rowMainListObj(数据绑定变量),BaseDiffUtilItemCallback()和该(ListItemOnClickListener实现类)。 最后,使用baseRecyclerViewAdapter.submitList(itemModelList),在回收者视图中填充数据。

You can also extend the adapter and other components to add additional functionalities. For example: if you need to inflate different rows in the list.

您还可以扩展适配器和其他组件以添加其他功能。 例如:如果您需要在列表中填充不同的行。

结果: (Result:)

Image for post

You can add this library to your app by adding these code:

您可以通过添加以下代码将此库添加到您的应用中:

project level build.gradleallprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
app level build.gradleimplementation 'com.github.tanveerprottoy:base-recyclerview-adapter:1.0'

The source is on Github base-recyclerview-adapter

来源在Github base-recyclerview-adapter上

That’s it for today. Hope this will be helpful to you. Thank you for reading. Please give some claps if you liked the post.

今天就这样。 希望对您有帮助。 感谢您的阅读。 如果您喜欢该帖子,请给您一些鼓掌。

翻译自: https://medium.com/dev-genius/creating-a-recyclerview-adapter-which-can-be-used-with-any-data-model-and-any-item-row-view-with-1144ca58f0be

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值