基于Dagger在Epoxy Controller中实现RecyclerView条目点击跳转的最佳方式
解决Airbnb Epoxy RecyclerView条目点击跳转Activity的Context问题
你的思路完全没问题,通过在EpoxyController中定义回调接口、让主Activity实现接口的方式,确实是Epoxy里处理条目交互的标准做法。我来把具体的代码细节补全,帮你搞定Context的问题:
步骤1:在EpoxyController中定义点击回调接口
首先在你的EpoxyController内部(或者单独定义,放在控制器里更内聚)创建一个接口,用来传递点击事件,方法参数带上View,这样就能通过View获取Context:
class YourEpoxyController : EpoxyController() { // 定义点击回调接口 interface OnItemClickListener { fun onItemClicked(item: YourDataModel, view: View) } // 持有回调实例 var itemClickListener: OnItemClickListener? = null override fun buildModels() { // 构建EpoxyModel时,把回调传递给每个model yourDataList.forEach { item -> YourItemModel_() .id(item.id) .data(item) .clickListener { view -> itemClickListener?.onItemClicked(item, view) } .addTo(this) } } }
步骤2:编写你的EpoxyModel
在对应的ItemModel中,添加clickListener的字段,用来接收点击回调(如果用注解生成Model,直接定义对应字段即可):
// 注解生成的EpoxyModel示例 @EpoxyModelClass(layout = R.layout.your_item_layout) abstract class YourItemModel : EpoxyModelWithHolder<YourItemModel.Holder>() { @EpoxyAttribute lateinit var data: YourDataModel @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var clickListener: ((View) -> Unit)? = null override fun bind(holder: Holder) { super.bind(holder) // 给条目根布局设置点击监听 holder.itemView.setOnClickListener { clickListener?.invoke(it) } // 绑定其他数据到View holder.titleTv.text = data.title } class Holder : EpoxyHolder() { lateinit var titleTv: TextView override fun bindView(itemView: View) { titleTv = itemView.findViewById(R.id.title_tv) } } }
步骤3:在主Activity中实现接口并初始化控制器
让主Activity实现刚才定义的OnItemClickListener接口,在回调方法里通过View的Context启动目标Activity:
class MainActivity : AppCompatActivity(), YourEpoxyController.OnItemClickListener { private lateinit var epoxyController: YourEpoxyController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化控制器并设置回调 epoxyController = YourEpoxyController().apply { itemClickListener = this@MainActivity } // 绑定控制器到RecyclerView val recyclerView = findViewById<RecyclerView>(R.id.recycler_view) recyclerView.setController(epoxyController) // 加载数据并刷新 loadData() } private fun loadData() { // 模拟数据加载 val dataList = listOf(YourDataModel(1, "测试条目1"), YourDataModel(2, "测试条目2")) epoxyController.setData(dataList) // 假设控制器有setData方法更新数据 } override fun onItemClicked(item: YourDataModel, view: View) { // 通过view.getContext()获取Context启动Activity val intent = Intent(view.context, TargetActivity::class.java) intent.putExtra("ITEM_ID", item.id) view.context.startActivity(intent) // 也可以直接用Activity本身(Activity是Context子类) // startActivity(Intent(this, TargetActivity::class.java).putExtra("ITEM_ID", item.id)) } }
额外注意点
- 若担心内存泄漏,可以用
WeakReference持有回调实例,只要控制器生命周期和Activity一致(比如在Activity销毁时把itemClickListener置为null),一般不会有问题。 - 如果用Java开发,核心逻辑完全一致,只需要调整语法细节即可。
内容的提问来源于stack exchange,提问作者nir
相关产品推荐
相关产品推荐

