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

Adapter类中viewModels委托引用未解析:无法在Adapter类中使用ViewModel实例(Fragment与Activity中可正常使用)

解决Adapter中无法使用viewModels()委托的问题

嘿,我懂你碰到的麻烦了!viewModels()这个委托是Google专门为Fragment和Activity设计的——因为这俩都是LifecycleOwner,能管理ViewModel的生命周期。但Adapter本质上只是个UI渲染工具类,不属于Android的生命周期组件体系,所以直接在Adapter里写by viewModels()肯定会报unresolved reference的错误。

下面给你几个靠谱的解决方案,按推荐程度排序:

1. 从宿主Fragment/Activity传递ViewModel实例(最推荐)

Adapter本来就是由Fragment或Activity创建的,咱直接在创建Adapter的时候把ViewModel传进去就行,既简单又符合MVVM的职责划分:

步骤1:在宿主Fragment/Activity中创建ViewModel

// 你的Fragment/Activity代码
private val queueViewModel: QueueViewModel by viewModels { 
    QueueViewModel.QueueDataViewModelFactory((requireActivity().application as DownloadManagerApplication).repository) 
}

// 创建Adapter时传入ViewModel
val yourAdapter = QueueItemAdapter(queueViewModel)
recyclerView.adapter = yourAdapter

步骤2:在Adapter中接收并使用ViewModel

class QueueItemAdapter(private val queueViewModel: QueueViewModel) : RecyclerView.Adapter<QueueItemAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // 正常创建ViewHolder
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // 直接使用queueViewModel处理逻辑,比如点击事件
        holder.itemView.setOnClickListener {
            queueViewModel.handleItemClick(yourDataList[position])
        }
    }
}

这种方式的好处是Adapter只负责UI渲染和事件转发,ViewModel的生命周期由宿主组件(Fragment/Activity)管理,完全符合MVVM的设计思想。

2. 通过数据流传递数据,让Adapter只处理UI(更优雅的MVVM实践)

如果不想让Adapter持有ViewModel引用,咱可以让ViewModel暴露StateFlow/Flow数据流,由Fragment/Activity观察数据变化,再把数据传递给Adapter更新UI:

步骤1:在ViewModel中暴露数据流

class QueueViewModel(private val repository: QueueRepository) : ViewModel() {
    // 用StateFlow暴露队列数据
    val queueItems: StateFlow<List<QueueItem>> = repository.getQueueItems()
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )

    // 处理业务逻辑的方法
    fun handleItemClick(item: QueueItem) {
        // 你的业务逻辑
    }
}

步骤2:在Fragment中观察数据并更新Adapter

// Fragment代码
private val queueViewModel: QueueViewModel by viewModels { 
    QueueViewModel.QueueDataViewModelFactory((requireActivity().application as DownloadManagerApplication).repository) 
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val adapter = QueueItemAdapter()
    recyclerView.adapter = adapter

    // 观察数据流,更新Adapter数据
    lifecycleScope.launch {
        queueViewModel.queueItems.collect { items ->
            adapter.submitList(items)
        }
    }

    // 如果需要处理点击事件,可以给Adapter设置回调
    adapter.onItemClick = { item ->
        queueViewModel.handleItemClick(item)
    }
}

步骤3:Adapter只处理UI和回调

class QueueItemAdapter : RecyclerView.Adapter<QueueItemAdapter.ViewHolder>() {
    var onItemClick: ((QueueItem) -> Unit)? = null
    private var dataList = emptyList<QueueItem>()

    fun submitList(newList: List<QueueItem>) {
        dataList = newList
        notifyDataSetChanged()
        // 或者用DiffUtil优化更新
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = dataList[position]
        holder.itemView.setOnClickListener {
            onItemClick?.invoke(item)
        }
        // 渲染UI
    }
}

这种方式让Adapter彻底和ViewModel解耦,只专注于UI渲染,是更纯粹的MVVM实践。

3. 手动通过ViewModelProvider获取(不推荐)

如果你非要在Adapter里直接获取ViewModel,也可以通过拿到宿主的LifecycleOwner(比如Activity/Fragment),用ViewModelProvider手动创建,但这种方式会让Adapter和宿主强耦合,不利于Adapter的复用,所以非常不推荐:

// 假设Adapter能拿到Activity的引用
val application = (activity?.application as DownloadManagerApplication)
val factory = QueueViewModel.QueueDataViewModelFactory(application.repository)
val queueViewModel = ViewModelProvider(activity!!, factory)[QueueViewModel::class.java]

内容的提问来源于stack exchange,提问作者Abdulsamet Kılınçarslan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:12:36