MVVM实现RecyclerView数据绑定

本文详细介绍如何在Android项目中使用DataBinding结合RecyclerView,实现自定义属性和事件回调接口,包括实体类、Adapter、RecyclerView的自定义及绑定过程。

使用过databing的开发人员,想必对它能够支持自定义属性并不陌生。本文也就是在此基础上,实现对RecyclerView的数据绑定。本文主要涉及到实体类:

  • UserBean:用户信息
  • BindAdapter:自定义Adapter
  • BindRecyclerView:自定义RecyclerView
  • OnRecyclerItemClickListener:事件回调接口
  • RecyclerViewBinding:自定义绑定属性

一、集成

在项目的gradle中配置如下:

android {
    ...
    dataBinding {
        enabled = true
    }
}

二、布局文件

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

    <data>
        <import type="com.xinyartech.mvvm.UserBean"/>
        <import type="androidx.databinding.ObservableList"/>

        <variable
            name="userList"
            type="ObservableList&lt;UserBean>" />

        <variable
            name="presenter"
            type="com.xinyartech.mvvm.DataBindingPresenter" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:id="@+id/load"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="加载更多"
            android:onClick="@{(view)->presenter.loadMore(userList)}"
            />

        <Button
            android:id="@+id/gc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="验证gc"
            />

        <com.xinyartech.mvvm.rv.BindRecyclerView
            android:layout_below="@+id/load"
            android:id="@+id/leftRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutId="@{@layout/adapter_item2}"
            app:list="@{userList}"
            app:itemClickListener="@{(item) -> presenter.itemClick((UserBean)item)}"
            />
    </RelativeLayout>
</layout>
2、adapter_item2.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="com.xinyartech.mvvm.rv.OnRecyclerItemClickListener"/>
        <variable
            name="item"
            type="com.xinyartech.mvvm.UserBean" />

        <variable
            name="itemOneClickListener"
            type="OnRecyclerItemClickListener" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:orientation="vertical">

        <TextView
            android:id="@+id/btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{item.userName}" />

    </LinearLayout>
</layout>

三、UserBean

public class UserBean extends BaseObservable {

    //方式1 BaseObservable+@Bindable+notifyPropertyChanged
    public String userName;


    //方式2 ObservableField
    public ObservableField<String> pwd = new ObservableField<>();

    @Bindable
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
        notifyPropertyChanged(BR.userName);
    }
}

有两种方式进行双向绑定实现

  • 实体类集成BaseObservable,并在getUserName()方法上添加@Bindable注解,在setUserName()方法内,通过notifyPropertyChanged()进行数据更新
  • 使用ObservableField标识属性。
    这里推荐使用第二种,简单易操作。

四、BinderAdapter

代码有点多,先贴出来,一步步理解。

public abstract class BindAdapter<T> extends RecyclerView.Adapter<BindAdapter.BindHolder> {


    private List<T> list = new ArrayList<>();
    private ObservableList<T> observableList;

    private OnRecyclerItemClickListener itemOneClickListener;

    public BindAdapter(final RecyclerView view, ObservableList<T> observableList) {

        this.observableList = observableList;
        this.list.addAll(observableList);

        //添加数据监听
        observableList.addOnListChangedCallback(new ObservableList.OnListChangedCallback<ObservableList<T>>() {
            @Override
            public void onChanged(ObservableList<T> sender) {

            }

            @Override
            public void onItemRangeChanged(ObservableList<T> sender, int positionStart,
                                           int itemCount) {
                notifyItemRangeChanged(positionStart,itemCount);
            }

            @Override
            public void onItemRangeInserted(final ObservableList<T> sender, final int positionStart,
                                            final int itemCount) {
                view.post(new Runnable() {
                    @Override
                    public void run() {
                        list.add(positionStart, sender.get(positionStart));
                        notifyItemRangeInserted(positionStart, itemCount);
                        view.scrollToPosition(positionStart);
                    }
                });

            }

            @Override
            public void onItemRangeMoved(ObservableList<T> sender, int fromPosition,
                                         int toPosition, int itemCount) {

            }

            @Override
            public void onItemRangeRemoved(ObservableList<T> sender, final int positionStart, final int itemCount) {
                view.post(new Runnable() {
                    @Override
                    public void run() {
                        if (itemCount == 1) {
                            list.remove(positionStart);
                            notifyItemRangeRemoved(positionStart, itemCount);

                            notifyItemRangeChanged(positionStart, getItemCount() - positionStart, new Object());

                        } else {
                            list.clear();
                            notifyDataSetChanged();
                        }
                    }
                });
            }
        });
    }

    public OnRecyclerItemClickListener getItemOneClickListener() {
        return itemOneClickListener;
    }

    public ObservableList<T> getObservableList() {
        return observableList;
    }

    public void setObservableList(ObservableList<T> observableList) {
        this.observableList = observableList;
    }

    public void setItemOneClickListener(OnRecyclerItemClickListener itemOneClickListener) {
        this.itemOneClickListener = itemOneClickListener;
    }

    public abstract int onCreateViewHolderLayoutId();

    @NonNull
    @Override
    public BindHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ViewDataBinding binding =
                DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
                        onCreateViewHolderLayoutId(), parent, false);


        return new BindAdapter.BindHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull BindHolder holder, final int position) {
        holder.bind(this.list.get(holder.getAdapterPosition()),
                new OnRecyclerItemClickListener() {
                    @Override
                    public void onRecyclerItemClick(Object item) {
                        if (itemOneClickListener != null) {

                            itemOneClickListener.onRecyclerItemClick(item);
                        }
                    }
                });

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (itemOneClickListener != null) {
                    itemOneClickListener.onRecyclerItemClick(getItem(position));
                }
            }
        });
    }

    public T getItem(int position) {
        if (position < this.list.size()) {
            return this.list.get(position);
        } else {
            return null;
        }
    }

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

    /**
     * 自定义ViewHolder
     */
    public static class BindHolder extends RecyclerView.ViewHolder {

        ViewDataBinding mBinding;

        public BindHolder(ViewDataBinding binding) {
            super(binding.getRoot());
            this.mBinding = binding;
        }

        public void bind(Object obj,
                         OnRecyclerItemClickListener itemOneClickListener) {
            this.mBinding.setVariable(BR.item, obj);
            this.mBinding.setVariable(BR.itemOneClickListener, itemOneClickListener);
            this.mBinding.executePendingBindings();

        }
    }
}

这里将代码分解成以下一个部分:

  • 自定义viewHodler
  • 绑定item布局
  • 添加绑定数据监听
  • 添加item点击事件监听
1、自定义ViewHolder、添加item点击事件
 public static class BindHolder extends RecyclerView.ViewHolder {

        ViewDataBinding mBinding;

        public BindHolder(ViewDataBinding binding) {
            super(binding.getRoot());
            this.mBinding = binding;
        }

        public void bind(Object obj,
                         OnRecyclerItemClickListener itemOneClickListener) {
            this.mBinding.setVariable(BR.item, obj);
            this.mBinding.setVariable(BR.itemOneClickListener, itemOneClickListener);
            this.mBinding.executePendingBindings();

        }
    }

赋值item和条目点击OnRecyclerItemClickListener ,点击事件需要配合holder.itemView.setOnClickListener使用。

2、绑定item布局
@Override
    public BindHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ViewDataBinding binding =
                DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
                        onCreateViewHolderLayoutId(), parent, false);


        return new BindAdapter.BindHolder(binding);
    }

其中 onCreateViewHolderLayoutId() == R.layout.adapter_item2.xml

3、添加绑定数据监听

通过设置 observableList.addOnListChangedCallback 监听list数据集合变化,并在回调中处理adapter的数据更新,代码如上。

五、BindRecyclerView

public class BindRecyclerView extends RecyclerView {

    public BindRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) {

        BindAdapter bindAdapter = getBindAdapter();
        if (bindAdapter != null && onRecyclerItemClickListener != null) {
            bindAdapter.setItemOneClickListener(onRecyclerItemClickListener);
        }

    }

    private BindAdapter getBindAdapter() {
        if (getAdapter() instanceof BindAdapter) {
            return (BindAdapter) getAdapter();
        }

        return null;
    }
}

六、OnRecyclerItemClickListener

public interface OnRecyclerItemClickListener {

    void onRecyclerItemClick(Object item);
}

七、RecyclerViewBinding

这里是重点部分,先贴代码

public class RecyclerViewBinding {

    @BindingAdapter(value = {"layoutId", "list","itemClickListener"
    }, requireAll = false)
    public static <T> void setAdapter(BindRecyclerView view,
                                      @LayoutRes final int layoutId,
                                      ObservableList<T> list,
                                      OnRecyclerItemClickListener itemClickListener){
        if (list == null) {
            return;
        }

        if (view.getLayoutManager() == null) {
            // default LinearLayoutManager 垂直布局
            LinearLayoutManager layoutManager = new LinearLayoutManager(
                    view.getContext(), LinearLayoutManager.VERTICAL, false);
            view.setLayoutManager(layoutManager);

            DividerItemDecoration decoration = new DividerItemDecoration(
                    view.getContext(), LinearLayoutManager.VERTICAL);
            //noinspection ConstantConditions 添加分割线
            //decoration.setDrawable(ContextCompat.getDrawable(view.getContext(), R.drawable.divider_gray));

            view.addItemDecoration(decoration);
        }
        //noinspection unchecked 绑定adpter
        BindAdapter<T> bindAdapter = (BindAdapter<T>) view.getAdapter();
        if (bindAdapter == null || !Objects.equals(bindAdapter.getObservableList(), list)) {

            //创建适配器
            bindAdapter = new BindAdapter<T>(view, list) {
                @Override
                public int onCreateViewHolderLayoutId() {
                    return layoutId;
                }
            };
        }

        //设置适配器
        view.setAdapter(bindAdapter);

        //item点击事件
        if (itemClickListener != null) {
            view.setOnRecyclerItemClickListener(itemClickListener);
        }
    }

}

添加@BindingAdapter注解,实现自定义属性layoutId(item布局文件)、list(数据集合)、itemClickListener(条目点击)。

以上就完成了自定义具有databinding功能的RecyclerView。其实最主要的还是自定义属性的使用,@BindingAdapter至关重要,如果需要自定义双向绑定就需要配合@InverseBindingAdapter使用了。

代码地址:

MVVM+RecycleView代码

内容概要:本文提出了一种基于改进扩散模型的高海拔地区新能源高波动出力场景生成方法,并提供了完整的Python代码实现。该方法针对高海拔地区风能、光伏等新能源出力波动剧烈、不确定性高的特点,通过优化扩散模型的结构与训练策略,有效捕捉历史数据的概率分布特征与时序相关性,从而生成高质量、多样化的出力场景。文中详细阐述了模型的数学推导、网络架构设计、损失函数优化及采样算法改进,并通过实验证明其在拟合精度、场景多样性与稳定性方面优于传统生成模型,为电力系统在高比例新能源接入下的规划、调度与风险评估提供了可靠的场景输入支持。; 适合人群:具备一定Python编程能力和机器学习基础,从事新能源发电预测、电力系统分析、智能优化、场景生成等方向研究的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①用于高海拔地区风电、光伏出力的不确定性建模与多场景生成;②支撑含高渗透率新能源的电力系统随机优化调度、鲁棒决策与风险评估;③为相关学术研究、论文复现与算法改进提供可运行的技术方案与代码基础; 阅读建议:建议读者结合所提供的完整资源(代码、数据集、说明文档)进行实践操作,重点关注扩散模型的前向加噪与反向去噪过程的设计细节,以及如何将其适配于新能源时序数据的生成任务,通过参数调优与对比实验深入理解模型的生成机制与性能边界。
内容概要:本文围绕基于静态约束法的配电网电动汽车接入容量评估展开研究,提出了一种在新型电力系统背景下评估主动配电网对电动汽车承载能力的方法。研究通过构建数学模型,结合潮流计算与关键约束条件(如电压越限、线路过载等),量化分析配电网可承受的最大电动汽车充电负荷容量,旨在识别规模化电动汽车接入带来的潜在运行风险,并为电网规划与运行提供科学依据。文中配套提供了完整的Matlab代码实现,便于仿真验证与结果复现。此外,该研究与分布式光伏承载力评估、电动汽车可调能力分析等方向形成技术联动,展现了多主题协同的研究体系。; 适合人群:具备电力系统分析基础理论知识及Matlab编程能力的高校研究生、科研机构研究人员,以及从事新能源并网、智能配电网规划与运行等相关领域的工程技术人员。; 使用场景及目标:①用于学术研究中的模型复现与论文撰写支撑;②评估实际配电网中电动汽车大规模接入的可行性与安全边界,指导充电基础设施布局;③作为高校教学案例,帮助学生深入理解电网承载力评估的核心原理、建模方法与仿真技术; 阅读建议:建议结合文中提及的相关研究方向(如二阶锥规划、多面体聚合方法等)进行对比学习,充分利用所提供的Matlab代码与网盘资料开展仿真实验,重点关注约束条件的设定逻辑与潮流计算模块的实现细节,以深化对评估模型机理与工程应用价值的理解。
内容概要:本文围绕“考虑隐私保护的分布式联邦学习电力负荷预测研究”展开,提出了一种基于Python实现的联邦学习框架,旨在解决居民或行业电力负荷预测中用户电表数据隐私泄露的风险。该研究通过构建分布式机器学习模型,使各参与方在不共享原始数据的前提下协同训练全局模型,有效实现了数据“可用不可见”。文中详细阐述了联邦学习的整体架构设计、本地模型训练流程、参数加密传输与安全聚合机制,并结合差分隐私等技术进一步增强系统的隐私保护能力。同时,研究利用真实电力负荷数据集进行了实验验证,展示了方法在预测精度与隐私保障之间的良好平衡,并提供了完整的代码实例与复现指南,便于后续研究与应用拓展。; 适合人群:具备一定机器学习基础和电力系统背景知识,从事智慧能源、隐私计算或人工智能相关方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 实现跨区域、跨主体的电力负荷协同预测,打破数据孤岛;② 在确保用户用电数据隐私安全的前提下提升负荷预测准确性;③ 推动联邦学习在智能电网、需求响应、虚拟电厂等场景中的实际部署与应用。; 阅读建议:建议结合文中提供的Python代码与网盘资料进行动手实践,重点关注联邦学习的通信轮次设计、模型聚合算法(如FedAvg)的实现细节以及差分隐私噪声添加策略,深入理解其对模型性能与隐私强度的影响,为进一步优化与创新奠定基础。
VDA_Band_19.1_3rd edition_2026 English Inspection of Technical Cleanliness 内容概要:本文档为德国汽车工业协会(VDA)发布的第三版《技术清洁度检验:功能相关汽车部件的颗粒污染检测》(VDA 19.1),系统规范了汽车行业中零部件技术清洁度的检测方法与流程。文件涵盖从取样、提取、过滤到分析的全流程标准化操作,重点更新了干法提取(如 Stamp Test 和刷吸法)、小于50µm颗粒的检测、光学子系统和SEM/EDX标准分析方法,并引入统一材料分类体系以提升结果可比性。同时明确了“标准分析”与“自由检验”的区别,前者用于高兼容性检测,后者允许客户与供应商协商定制参数。文档还强化了对非可测组件的技术清洁保障、测量不确定度评估及方法验证的要求,并提供了多个实际案例支持应用落地。; 适合人群:适用于汽车制造业中从事质量控制、工艺开发、供应商管理及相关检测实验室的技术人员和管理人员,尤其适合具备一定质量管理或洁净度检测基础的专业人员。; 使用场景及目标:①用于制定和执行零部件清洁度检测标准;②指导 incoming/outgoing 检验及生产过程监控;③支持失效分析与质量改进项目;④作为企业内部审核和技术交流的依据; 阅读建议:建议结合VDA 19.2及其他相关标准配套使用,重点关注各章节中的起始参数设定、方法选择逻辑及附录中的检查表示例,在实际操作中同步开展方法验证与人员培训,确保检测结果的有效性和可追溯性。
内容概要:本研究聚焦于电动汽车(EV)作为灵活可调资源的能力评估,提出了一种基于多面体聚合与闵可夫斯基和的数学建模方法,用以精确刻画大规模电动汽车集群的可调能力范围。通过将单辆电动汽车的充放电行为抽象为几何空间中的多面体可行域,并利用闵可夫斯基和实现对群体可行域的高效聚合,从而构建出能够反映整体调节潜力的统一数学表达。该方法在Matlab平台上实现了完整的仿真代码,支持对不同场景下电动汽车集群的上、下调能力进行量化评估,为电网调度、需求响应及电力市场机制设计提供了理论依据与工具支撑。; 适合人群:具备电力系统分析、优化理论及Matlab编程基础的研究生、科研人员及从事新能源、智能电网相关工作的工程师。; 使用场景及目标:①用于评估大规模电动汽车接入背景下系统的灵活性资源潜力;②支撑含高比例可再生能源的电力系统调度与规划决策;③为需求响应项目中EV聚合商参与电力市场提供能力申报的技术手段;④作为教学案例帮助理解集合运算在电力系统中的应用。; 阅读建议:学习者应结合Matlab代码深入理解多面体建模与闵可夫斯基和的实现细节,建议从单车模型入手逐步过渡到集群聚合,并尝试调整参数(如数量、SOC分布、功率限制)观察聚合结果的变化,以增强对模型特性的掌握。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值