You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin技术问题:如何从SharedViewModel向Adapter传递数据

如何在RecyclerView Adapter中访问SharedViewModel的数据?

核心原则

Adapter的职责是仅负责UI渲染和用户交互的分发,不应该直接持有ViewModel引用或访问ViewModel数据。正确的做法是由宿主Fragment/Activity将ViewModel的数据传递给Adapter,或者通过回调让Fragment处理ViewModel相关操作。


方法一:直接传递ViewModel数据给Adapter

将ViewModel中的数据作为参数传入Adapter,若数据是LiveData则观察其变化并更新Adapter:

1. 在Fragment中初始化Adapter并传递数据

class DeactivatedJumpElementsFragment : Fragment(R.layout.deactivated_jump_elements_fragment) {
    private lateinit var sharedViewModel: DeactivatedElementsViewModel
    private lateinit var myAdapter: MyAdapter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 获取共享ViewModel(注意用requireActivity()确保跨Fragment共享)
        sharedViewModel = ViewModelProvider(requireActivity())[DeactivatedElementsViewModel::class.java]
        
        // 初始化Adapter并传入初始数据
        val initialData = sharedViewModel.elementsFromStand
        myAdapter = MyAdapter(initialData)
        yourRecyclerView.adapter = myAdapter

        // 若数据是LiveData,观察变化并更新Adapter
        sharedViewModel.elementsFromStandLiveData.observe(viewLifecycleOwner) { newData ->
            myAdapter.updateData(newData)
        }
    }
}

2. 在Adapter中持有数据并提供更新方法

class MyAdapter(private var elementsData: Map<String, Array<Any>>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
    // 提供数据更新方法,可配合DiffUtil实现高效刷新
    fun updateData(newData: Map<String, Array<Any>>) {
        elementsData = newData
        notifyDataSetChanged()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // 直接使用已传递的elementsData渲染UI
        val entry = elementsData.entries.elementAt(position)
        holder.itemText.text = entry.key
        // ...其他UI操作
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val itemText: TextView = itemView.findViewById(R.id.item_text)
        // ...其他视图引用
    }
}

方法二:通过回调让Fragment处理ViewModel操作

如果Adapter需要触发ViewModel的修改操作(比如点击按钮更新数据),定义回调接口让Fragment处理:

1. 定义回调接口

interface ElementActionCallback {
    fun onElementButtonClicked(elementKey: String)
}

2. Adapter接收回调并分发事件

class MyAdapter(
    private val elementsData: Map<String, Array<Any>>,
    private val callback: ElementActionCallback
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val entry = elementsData.entries.elementAt(position)
        holder.actionButton.setOnClickListener {
            // 将点击事件分发给Fragment处理
            callback.onElementButtonClicked(entry.key)
        }
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val actionButton: Button = itemView.findViewById(R.id.action_button)
        // ...其他视图引用
    }
}

3. Fragment实现回调并操作ViewModel

class DeactivatedJumpElementsFragment : Fragment(R.layout.deactivated_jump_elements_fragment), ElementActionCallback {
    private lateinit var sharedViewModel: DeactivatedElementsViewModel

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        sharedViewModel = ViewModelProvider(requireActivity())[DeactivatedElementsViewModel::class.java]
        val initialData = sharedViewModel.elementsFromStand
        myAdapter = MyAdapter(initialData, this)
        yourRecyclerView.adapter = myAdapter
    }

    override fun onElementButtonClicked(elementKey: String) {
        // 在Fragment中操作ViewModel
        sharedViewModel.updateElementStatus(elementKey)
    }
}

为什么你的之前方法失败?

  1. 直接在Adapter中实例化ViewModel:Adapter没有关联的LifecycleOwner(Fragment/Activity),ViewModel需要依附于宿主的生命周期,因此会报"Can't access ViewModels from detached fragment"错误。
  2. 创建新的Fragment实例获取数据:DeactivatedJumpElementsFragment()是一个全新的、未初始化的Fragment实例,和当前显示的Fragment不是同一个对象,其ViewModel自然未初始化。

内容的提问来源于stack exchange,提问作者Malte Ge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:12:47