如何在不同Fragment的自定义View间共享Activity级ViewModel?
解决自定义View共享Activity级ViewModel的问题
你的核心问题是findViewTreeViewModelStoreOwner()会返回包裹自定义View的Fragment(最近的ViewModelStoreOwner),导致每个Fragment下的自定义View拿到的是Fragment级的ViewModel实例,而非Activity级的共享实例。下面是几种可行的解决办法:
方法一:手动传递Activity的ViewModelStoreOwner
在Fragment中拿到Activity级的ViewModelStoreOwner,直接传递给自定义View:
- 自定义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 } }
- 在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接口):
- 添加扩展函数
fun View.findActivityViewModelStoreOwner(): ViewModelStoreOwner? { var currentContext = context while (currentContext is ContextWrapper) { if (currentContext is ViewModelStoreOwner) { return currentContext } currentContext = currentContext.baseContext } return null }
- 自定义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
相关产品推荐
相关产品推荐

