Adapter类中viewModels委托引用未解析:无法在Adapter类中使用ViewModel实例(Fragment与Activity中可正常使用)
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

