函数返回RecyclerView等View而非ID是否属于不良编程实践?
关于返回View对象而非ID是否为不良实践的分析
嘿,这个问题问得相当务实,咱们结合你的具体实现场景来一步步聊清楚。
先明确核心问题:返回View对象算不算不良实践?
答案是:本身不算不良实践,但要根据场景注意潜在风险。咱们对比下返回ID和返回View的差异:
- 返回ID的方式(比如传统的
findViewById):每次使用都要重新查找View,虽然现在有DataBinding、ViewBinding帮我们缓存,但如果父类需要频繁操作这个View,重复查找多少有点冗余。而且父类拿到ID后还得自己去实例化View,增加了父类的代码复杂度。 - 返回View对象的方式:直接拿到已经初始化好的View实例,减少了重复查找的开销,父类可以直接调用View的方法(比如
setAdapter、smoothScrollToPosition),逻辑更简洁高效。
但这种方式需要注意几个坑:
- 内存泄漏风险:如果父类在Fragment生命周期之外(比如Fragment已经销毁)还持有这个View的引用,就可能导致内存泄漏。不过你的场景里,BaseFragment是子类的父类,父类调用
getRecyclerView()拿到的View和子类的生命周期绑定,只要父类不在Fragment生命周期外(比如异步任务里)持有这个引用,就不会有问题。 - 耦合性问题:BaseFragment强制子类返回
RecyclerView,意味着所有继承它的Fragment都必须包含RecyclerView。如果以后有子类不需要RecyclerView,这个BaseFragment就不适用了,但你的当前场景是多个Fragment都用RecyclerView,这种耦合是合理的,属于为了复用通用逻辑而做的必要约束。 - View的初始化时机:必须确保调用
getRecyclerView()时,DataBinding已经初始化完成(也就是View已经被创建)。比如不能在onCreate()里调用,得在onViewCreated()之后,否则会拿到null。你需要保证BaseFragment里调用这个方法的时机是正确的。
针对你的具体实现:合理且高效的封装
你的实现方式(BaseFragment定义抽象方法,子类通过DataBinding返回RecyclerView)其实是非常合适的,原因如下:
- 利用DataBinding的优势:DataBinding已经帮我们完成了View的查找和缓存,子类返回的
binding.recyclerViewLayoutId是已经初始化好的实例,避免了重复查找,效率更高。 - 统一父类逻辑:父类可以通过这个抽象方法拿到RecyclerView,统一处理通用逻辑,比如设置默认的
LayoutManager、添加分割线、初始化Adapter等,减少子类的重复代码,完全符合DRY(Don't Repeat Yourself)原则。 - 强制子类规范:抽象方法保证了所有子类都必须提供RecyclerView,避免了父类逻辑因为子类缺失View而崩溃,提高了代码的健壮性。
一些优化小建议
- 缓存View实例:可以在BaseFragment里缓存第一次拿到的RecyclerView,避免每次调用
getRecyclerView()都从Binding里获取(虽然Binding本身也是缓存的,但这样更直观):private RecyclerView mRecyclerView; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mRecyclerView = getRecyclerView(); // 后续父类的所有操作都使用mRecyclerView即可 } - 避免过度设计:如果你的场景里所有子类都需要RecyclerView,当前的设计就足够了。如果以后有扩展需求,可以考虑用接口或者泛型来增强灵活性,但现在没必要提前过度设计。
- 注意生命周期边界:不要在Fragment的
onDestroyView()之后再调用getRecyclerView(),因为此时View已经被销毁,Binding也可能被置为null,会导致空指针异常。
总结
你的这种实现不仅不是不良编程实践,反而在你的场景下是一种高效、合理的封装方式。只要注意View的初始化时机和生命周期内的引用管理,就可以放心使用。
内容的提问来源于stack exchange,提问作者bycfly
相关产品推荐
相关产品推荐

