RecyclerView中ViewHolder已实现点击监听为何还要用点击接口?
RecyclerView item点击监听:为什么推荐用构造传入接口的实现
你当前在ViewHolder内部直接写点击监听的写法确实可以正常运行,但本质是把业务逻辑和Adapter的视图绑定逻辑强耦合在了一起,在以下场景里,通过构造传入自定义点击接口的实现会合适得多:
- 同一个Adapter需要在多个页面/业务场景复用时
如果你写的是通用列表Adapter,比如商品列表、消息列表,会在首页、搜索页、收藏页等多个页面用到,不同页面点击同一个控件的逻辑往往完全不同:首页点商品按钮直接进详情页,搜索页点击要先上报搜索词埋点再进详情,收藏页点击可能先弹取消收藏的二次确认框。如果把点击逻辑写死在ViewHolder里,你每次复用Adapter都要修改内部的判断代码,甚至要加很多区分当前页面的标识字段,维护成本极高。用接口传入的方式,你只需要在不同页面初始化Adapter时传入对应逻辑的接口实现,Adapter本身的代码不需要做任何修改。 - 点击逻辑需要依赖页面独有的生命周期、组件或状态时
点击item后的常见操作:弹出依附于Activity的Dialog、调用当前页面ViewModel的请求方法、通过Navigation组件跳转页面、更新页面顶部/底部的非列表控件(比如购物车角标),这些逻辑都需要依赖Activity/Fragment持有的对象。如果把逻辑写在Adapter里,你需要把Activity、ViewModel、NavController等大量对象传入Adapter,不仅会大幅提升耦合度,还很容易引发内存泄漏。通过接口回调的方式,点击事件会直接抛回给持有这些资源的Activity/Fragment处理,Adapter不需要感知上层的任何实现细节。 - 需要支持多控件、多类型点击的扩展场景时
一个列表item往往不止一个可点击区域:除了你现在写的按钮,可能还有整个item的点击、头像的点击、删除按钮的点击、复选框的选中回调。如果把所有点击逻辑都写在ViewHolder的onClick方法里,很快就会堆上大量的viewId判断、分支逻辑。用接口的方式你可以灵活定义不同的回调方法,甚至可以根据需求拆分成多个独立的点击接口,代码结构会清晰很多,也不会出现ViewHolder里堆几百行业务逻辑的情况。 - 需要编写单元测试时
把点击逻辑写死在Adapter内部,测试点击逻辑时必须连带初始化RecyclerView、Adapter、itemView等一整套安卓组件,测试成本很高。用接口实现的话,点击后的业务逻辑完全和Adapter解耦,你可以直接对接口的实现逻辑做单元测试,不需要依赖任何UI组件。
补充:不是说你当前的写法完全不能用,如果这个Adapter只在唯一的固定页面使用、点击逻辑非常简单且后续不会有扩展需求,直接在ViewHolder里写监听确实能少写几行接口代码。但只要后续有复用、扩展、和页面交互的需求,写死在ViewHolder里的逻辑会很快变成难以维护的“面条代码”。
你提到的接口传入方式,只需要在原来的点击回调里加一行调用即可,不需要改动其他基础逻辑:
@Override public void onClick(View v) { if (v.getId() == R.id.b1) { int position = getAdapterPosition(); // 注意要判断position有效性,避免点击item动画时position为-1的异常 if (position != RecyclerView.NO_POSITION && mMyClickListener != null) { // 直接把当前位置对应的数据、position回传给上层 mMyClickListener.onItemButtonClick(dataList.get(position), position); } } }
内容的提问来源于stack exchange,提问作者nano tech
相关产品推荐
相关产品推荐

