如何在DataBinding+RecyclerView中实现列表项点击跳转详情页?
实现RecyclerView列表项点击跳转的优雅方案
问题背景
前端转Kotlin开发Android应用,已基于DataBinding、Koin、Room搭建了展示法国省份列表的项目,用DataBinding实现了RecyclerView的自定义Adapter,但不知道如何优雅实现列表项点击跳转详情页的逻辑:
- 尝试过给Adapter关联ViewModel,但ViewModel没有Context无法启动Activity
- 希望在Adapter中传入点击函数,但不知道如何在XML中绑定该函数
解决方案
我们可以通过给Adapter传递点击回调lambda,结合DataBinding在XML中直接绑定点击事件的方式实现,具体步骤如下:
1. 修改Adapter,添加点击回调参数
更新DepartmentListAdaptater,添加接收点击事件的lambda参数,并在绑定数据时将回调传递给XML:
class DepartmentListAdaptater( private val onDepartmentClick: (Department) -> Unit ) : RecyclerView.Adapter<DepartmentListAdaptater.ViewHolder>() { private var dataSet: List<Department>? = null inner class ViewHolder(private val binding: DepartmentListRowBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(department: Department) { binding.department = department // 将点击回调传递给Binding binding.onDepartmentClick = onDepartmentClick } } fun submitList(list: List<Department>) { dataSet = list notifyDataSetChanged() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = DepartmentListRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) return ViewHolder(binding) } override fun getItemCount(): Int = dataSet?.size ?: 0 override fun onBindViewHolder(holder: ViewHolder, position: Int) { dataSet?.get(position)?.let { holder.bind(it) } } }
2. 修改XML布局,绑定点击事件
在department_list_row.xml的<data>块中添加点击回调变量,并给可点击的LinearLayout绑定点击事件:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="department" type="com.navalex.francemap.data.entity.Department" /> <!-- 添加点击回调变量,类型为接收Department参数的函数 --> <variable name="onDepartmentClick" type="kotlin.jvm.functions.Function1<com.navalex.francemap.data.entity.Department, kotlin.Unit>" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="72dp"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:background="@drawable/list_item_bg" android:layout_alignParentEnd="true" android:layout_alignParentTop="true" android:layout_alignParentBottom="true" android:clickable="true" <!-- 绑定点击事件,触发回调并传入当前department --> android:onClick="@{() -> onDepartmentClick.invoke(department)}" tools:ignore="UselessParent"> <TextView android:id="@+id/textView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingRight="16dp" android:text="@{department.nom}" android:paddingLeft="16dp"/> </LinearLayout> </RelativeLayout> </layout>
3. 在MainActivity中实现跳转逻辑
创建Adapter时传入点击回调lambda,在其中启动详情页(假设详情页为DepartmentDetailActivity,需传递省份数据):
class MainActivity : AppCompatActivity() { private val mViewModel: DepartmentsViewModel by viewModel() private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.toolbar.title = "Liste des départements" // 创建Adapter时传入点击回调 val adapter = DepartmentListAdaptater { department -> // 启动详情页,传递省份数据 val intent = Intent(this, DepartmentDetailActivity::class.java) // 需确保Department实现Parcelable/Serializable接口 intent.putExtra("DEPARTMENT_DATA", department) startActivity(intent) } binding.recyclerview.adapter = adapter binding.recyclerview.layoutManager = LinearLayoutManager(this) mViewModel.allDepartments.observe(this, Observer { data -> adapter.submitList(data) }) } }
补充说明
- 需确保
Department类实现Parcelable或Serializable接口,才能通过Intent传递对象 - 该方案将跳转逻辑与Adapter解耦,Adapter仅负责展示数据和传递点击事件,跳转逻辑由Activity处理,符合单一职责原则
- 避免在Adapter中持有Context,降低内存泄漏风险
内容的提问来源于stack exchange,提问作者Navalex
相关产品推荐
相关产品推荐

