创建 ViewModel 或 AndroidViewModel 的方法
Posted 小陈乱敲代码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建 ViewModel 或 AndroidViewModel 的方法相关的知识,希望对你有一定的参考价值。
有几种方法可以创建ViewModel和androidViewModel. 本文向您展示了创建它们的 Kotlin 示例。
这是您可能拥有的示例ViewModel或课程。AndroidViewModel
class MyViewModel: ViewModel()
class MyAndroidViewModel (app: Application)
: AndroidViewModel(app)
这里的代码示例用于片段类。所以它可能在活动类中不起作用。如果您将它们复制并粘贴到您的活动类中,则需要进行少量修改。
如果你不熟悉 Kotlin,可以先通过这里的一些简单示例 来了解一些重要的概念,例如“委托”。
手动创建 - 不要这样做!
private val viewModel = MyViewModel()
private val androidViewModel =
MyAndroidViewModel(requireActivity().application)
这只有在你不旋转手机的情况下才有效。当你旋转手机时,一个活动或片段被破坏并重新创建。将再次创建ViewModel或AndroidViewModel的新实例。因此,屏幕旋转之前的所有数据都会丢失。这违背了ViewModel架构的目的。您希望ViewModel通过活动或片段破坏存活下来。
我犯了这个错误,因为我不理解使用ViewModelProvider创建ViewModel的原因。
带有 ViewModelProvider 的 lateinit var
private lateinit var viewModel: MyViewModel
private lateinit var androidViewModel: MyAndroidViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
androidViewModel =
ViewModelProvider(this).get(MyAndroidViewModel::class.java)
使用ViewModelProvider是正确的创建方式ViewModel。创建活动或片段时,ViewModelProvider它足够聪明,可以重用第一个创建的ViewModel实例。
如果ViewModel没有改变(这很可能是真的),val在这里使用 Kotlin 变量是一个更好的选择。
通过使用ViewModelProvider
要使用val变量,请使用by lazy属性初始化。首次访问变量时,将执行委托块。
private val viewModel: MyViewModel by lazy
ViewModelProvider(this).get(MyViewModel::class.java)
private val androidViewModel: MyAndroidViewModel by lazy
ViewModelProvider(this).get(MyAndroidViewModel::class.java)
代码看起来比lateinit var解决方案干净得多。然而,另一种优雅的方式是使用by viewModelsor by activityViewModels。
通过视图模型/活动视图模型
要使用此属性委托,需要将以下依赖项添加到 build.gradle(模块级)。该版本只是一个示例,您可以使用更高版本或最新版本。
implementation 'androidx.fragment:fragment-ktx:1.3.6'
下面的代码太棒了!它本质上与by lazy不需要指定ViewModelProvider. 它会自动为您计算出来。
private val viewModel: MyViewModel by viewModels()
private val androidViewModel: MyAndroidViewModel by viewModels()
如果您想ViewModel在同一活动中共享不同的片段。您可以使用by activityViewModels.
private val viewModel: MyViewModel by activityViewModels()
private val androidViewModel: MyAndroidViewModel
by activityViewModels()
通过 viewModels(自定义构造函数参数)
ViewModel将其他对象传递给构造函数是很常见的。以下示例将Repository对象传递到MyViewModeland MyAndroidViewModel。
class MyViewModel(private val repository: Repository)
: ViewModel()
class MyAndroidViewModel(app: Application, repository: Repository)
: AndroidViewModel(app)
有一个自定义的构造函数参数ViewModel有点复杂。您需要有一个自定义ViewModel工厂来创建您的ViewModel.
要创建自定义ViewModel工厂,您可以继承自ViewModelProvider.NewInstanceFactory.
class MyViewModelFactory(private val repository: Repository)
: ViewModelProvider.NewInstanceFactory()
override fun <T : ViewModel> create(modelClass: Class<T>): T
if (modelClass.isAssignableFrom(MyViewModel::class.java))
return MyViewModel(repository) as T
throw IllegalArgumentException("Unknown ViewModel class")
对于自定义AndroidViewModel工厂,您可以继承自ViewModelProvider.AndroidViewModelFactory
class MyAndroidViewModelFactory(
private val app: Application,
private val repository: Repository)
: ViewModelProvider.AndroidViewModelFactory(app)
override fun <T : ViewModel> create(modelClass: Class<T>): T
if (modelClass.isAssignableFrom(
MyAndroidViewModel::class.java))
return MyAndroidViewModel(app, repository) as T
throw IllegalArgumentException("Unknown ViewModel class")
事实上,我们可以只实现ViewModelProvider.Factoryinterfacefor both MyViewModelFactoryand MyAndroidViewModelFactory。可以在此处找到示例。
要ViewModel使用自定义构造函数参数创建,请使用by viewModels委托属性。
private val viewModel: MyViewModel by viewModels
MyViewModelFactory(Repository())
private val androidViewModel: MyAndroidViewModel by viewModels
MyAndroidViewModelFactory(
requireActivity().application,
Repository())
如果您希望您在同一活动中的不同片段中生存,您可以替换by viewModels为。by ActivityViewModelsViewModel
private val viewModel: MyAndroidViewModel by activityViewModels
MyViewModelFactory(Repository())
private val androidViewModel: MyAndroidViewModel
by activityViewModels
MyAndroidViewModelFactory(
requireActivity().application,
Repository())
[更新 - 2021 年 11 月 7 日]:您也可以使用by lazyandViewModelProvider()代替,by viewModels它应该仍然可以工作。它不能用于替换by activityViewModels,因为创建的ViewModel不会在不同的片段之间共享。因此,这仅供您参考和了解。
private val viewModel: MyViewModel by lazy
val factory = MyViewModelFactory(Repository())
ViewModelProvider(this, factory).get(MyAndroidViewModel::class.java)
private val viewModel: MyAndroidViewModel by lazy
val factory = MyAndroidViewModelFactory(
requireActivity().application,
Repository())
ViewModelProvider(this, factory).get(MyAndroidViewModel::class.java)
我的常见做法
编程的有趣之处在于有很多方法可以做同样的事情。了解差异,让你成为更好的程序员。
我默认使用最后一种方法,因为我的 ViewModel 中通常有自定义构造函数参数。
此外,我通常使用by activityViewModels而不是by viewModels,这样可以跨不同片段共享数据。这节省了我研究如何将数据传递到不同片段的时间。例如,使用Bundleto在片段之间共享数据。
默认情况下,我也使用AndroidViewModel而不是ViewModel,因为我通常需要从应用程序上下文访问字符串资源和系统服务。网上正在讨论一些缺点,但我还没有完全理解这一部分。目前,AndroidViewModel对我来说很好。
这些是我的常见做法。我不确定其他安卓开发者是否同意我的观点。请告诉我你的想法。
以上是关于创建 ViewModel 或 AndroidViewModel 的方法的主要内容,如果未能解决你的问题,请参考以下文章