ViewModelProviders 在我的 Fragment 中不起作用
Posted
技术标签:
【中文标题】ViewModelProviders 在我的 Fragment 中不起作用【英文标题】:ViewModelProviders is not working inside my Fragment 【发布时间】:2019-11-10 15:42:49 【问题描述】:这就是我想要做的。
在 Fragment 内设置对象的ArrayList
从FragmentActivity
中的观察者那里获取该数组
容器(承载所有片段的活动)
所以,我所做的是以下。
首先我创建了SharedViewModel
,我将从那里设置和获取数据:
SharedViewModel.kt
class SharedViewModel: ViewModel()
var personArrayObj:MutableLiveData<ArrayList<Person>> = MutableLiveData()
fun setPersonArray(personArray:ArrayList<Person>)
personArrayObj.value = personArray
val getPersonArray:LiveData<ArrayList<Person>>
get() = personArrayObj
现在,我在托管所有片段创建的MainActivity
中实例化这个ViewModel
,所以,我可以从片段集的任何位置获取ArrayData
:
MainActivity.kt
class MainActivity: FragmentActivity()
private lateinit var viewModel:SharedViewModel
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
viewModel.getPersonArray.observe(this, Observer it:ArrayList<Person>
Log.d("Array:",""+it)
)
然后我需要做的最后一件事是从我想要的任何 Fragment 设置该 Array 的值,然后如果值发生更改,将触发主机 Activity,所以,要做到这一点,我简单地做一个 @ 987654331@ 在我想要的 Fragment 上。
问题
当我尝试在任何片段中实例化 SharedViewModel
时,我遇到了这个问题:
我试图断言!对于 null,也可以使用 let,但它不起作用,我想知道 FragmentActivity
是从哪里来的
如果我使用 viewLifecycleOwner
而不是 activity
它告诉我它不能用 Fragment 或 FragmentActivity 调用?
有什么线索吗?
谢谢。
【问题讨论】:
【参考方案1】:Fragments 提供了一个辅助方法来检索非空 Activity - requireActivity()
。用它代替activity
:
viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)
作为替代方案,您可以在应用中包含 fragment-ktx
依赖项并使用 by activityViewModels() Kotlin 属性扩展而不是使用 ViewModelProviders.of()
:
val viewModel: SharedViewModel by activityViewModels()
【讨论】:
使用requireActivity()
或多或少等同于使用activity!!
。应用程序将崩溃。在IllegalStateException
或 NPE 上。
@MarošŠeleng - 在这种情况下,来自诸如onViewCreated()
之类的生命周期方法,它永远不会崩溃,因此无论您抑制lint 警告,使用!!
还是使用requireActivity()
您将获得所有三个相同的运行时行为。
确实如此,但您在回答中没有提及任何这些,一般而言,这是一种不好的做法。我想我们都知道,Fragment 的生命周期到底有多大,为什么不一直把它写成安全的呢?
@MarošŠeleng - requireActivity()
在onViewCreated()
中绝对安全,这就是为什么我的回答指出,当您作为开发人员时,它是获取非空活动实例的正确方法,可以保证activity必须是非空的。
你能指导我@ianhanniballake 我最新的问题吗?谢谢【参考方案2】:
ViewModelProviders.of() 已被弃用。所以,我们可以像下面这样初始化视图模型。
viewModel = ViewModelProvider(requireActivity()).get(SampleViewModel::class.java)
【讨论】:
【参考方案3】:好的,我没看到
我在我的 Fragment 中创建了一个 viewModel
实例,在我的 MainActivity 中创建了另一个实例,所以这样做,我们会阻止观察者工作。
为了解决这个问题,我只是做了一个简单的方法,它返回我在MainActivity
中创建的实例
fun getViewModelInstance():SharedViewModel = viewModel
然后我只需从任何 Fragment 调用该实例来使用它
(activity as MainActivity).getViewModelInstance().setPersonArray(personArray)
【讨论】:
当您使用ViewModelProvider.of()
并传入您的活动时,您将获得与活动中完全相同的实例,因此您的想法是正确的。只有当您从 Fragment 中传入 this
时,您才能创建一个与 Fragment 相关联的全新 ViewModel。
你不想那样做,如果你想用和activity中一样的,就用activity scope吧。
非常有帮助。也被困在这里。谢谢极客!【参考方案4】:
基本上,问题是在您的片段类中 activity context 将是 nullable 并且 ViewModelPorviders
需要 Non-null context 才能使用.
一种解决方案是让您的 ViewModel
对象 可为空 (因为您的活动是可为空的) 在您的片段中,如下所示:
var viewModel: SharedViewModel? = null
然后在初始化期间,
viewModel = activity?.let ViewModelProviders.of(it).get(SharedViewModel::class.java)
【讨论】:
【参考方案5】:把东西放在 onActivityCreated() 而不是 onCreateView()... 这将解决 getActivity() 可为空的问题...... 因为根据一个fragment的生命周期,onActivityCreated()是在onCreareView()之后... 并且活动是在 onActivityCreated() 的调用上创建的...... 因此,getActivity() 将返回刚刚创建的活动
【讨论】:
以上是关于ViewModelProviders 在我的 Fragment 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
无法解析 AppCompatActivity 上的符号 ViewModelProviders
ViewModelProviders 在 1.1.0 中已弃用
由于不推荐使用 ViewModelProviders.of(),我应该如何创建 ViewModel 的对象?
cakephp 4 中的 I18n::setLocale('en_FR') 是不是正确?