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

如何在不同Fragment的自定义View间共享Activity级ViewModel?

解决自定义View共享Activity级ViewModel的问题

你的核心问题是findViewTreeViewModelStoreOwner()会返回包裹自定义View的Fragment(最近的ViewModelStoreOwner),导致每个Fragment下的自定义View拿到的是Fragment级的ViewModel实例,而非Activity级的共享实例。下面是几种可行的解决办法:

方法一:手动传递Activity的ViewModelStoreOwner

在Fragment中拿到Activity级的ViewModelStoreOwner,直接传递给自定义View:

  1. 自定义View中添加方法接收ViewModelStoreOwner
class MyCustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private lateinit var viewModelStoreOwner: ViewModelStoreOwner
    private val mainViewModel by lazy {
        ViewModelProvider(viewModelStoreOwner).get<MainViewModel>()
    }

    // 暴露方法给Fragment设置ViewModelStoreOwner
    fun setViewModelStoreOwner(owner: ViewModelStoreOwner) {
        this.viewModelStoreOwner = owner
    }
}
  1. 在Fragment中初始化自定义View时传入Activity实例
class MyFragment : Fragment() {
    private val mainViewModel: MainViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val customView = view.findViewById<MyCustomView>(R.id.my_custom_view)
        // 传入Activity作为ViewModelStoreOwner
        customView.setViewModelStoreOwner(requireActivity())
    }
}

方法二:自动向上查找Activity作为ViewModelStoreOwner

写一个扩展函数,从当前View向上遍历,找到所属的Activity(Activity本身实现了ViewModelStoreOwner接口):

  1. 添加扩展函数
fun View.findActivityViewModelStoreOwner(): ViewModelStoreOwner? {
    var currentContext = context
    while (currentContext is ContextWrapper) {
        if (currentContext is ViewModelStoreOwner) {
            return currentContext
        }
        currentContext = currentContext.baseContext
    }
    return null
}
  1. 自定义View中使用该扩展函数初始化ViewModel
class MyCustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val mainViewModel by lazy {
        val owner = findActivityViewModelStoreOwner()!!
        ViewModelProvider(owner).get<MainViewModel>()
    }
}

原方法失效原因

findViewTreeViewModelStoreOwner()的逻辑是查找当前View树中最近的ViewModelStoreOwner实现组件,而Fragment本身也实现了该接口,所以自定义View会优先绑定到包裹它的Fragment,导致创建Fragment级的ViewModel,无法跨Fragment共享。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:29:56