如何在 AndroidX 中实例化 ViewModel?
Posted
技术标签:
【中文标题】如何在 AndroidX 中实例化 ViewModel?【英文标题】:how to instantiate ViewModel In AndroidX? 【发布时间】:2019-06-16 05:30:18 【问题描述】:我想使用androidx库在Activity中初始化ViewModel
我已经尝试过文档中的说明,但它不起作用。 “.of”未解析。
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.myapplication.databinding.ActivityMainBinding`
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.setLifecycleOwner(this)
var model = ViewModelProvider.of(this).get(SheduleViewModel::class.java)
of 没有解决,也许在 androidx 中还有其他方法可以解决
【问题讨论】:
什么是this
?是AppCompatActivity
还是FragmentActivity
?还是 AndroidX Fragment
?还是别的什么?
需要导入ViewModelProviders
才能找到of
it appCompatActivity,我可以导入 ViewModelProvider 但它不包含方法
请给出一个完整的代码示例。显示周围的类和适当的导入。另外,复制粘贴 exact 错误消息。
你需要使用ViewModelProviders
类,尽管ViewModelProvider
。
【参考方案1】:
更新答案:
事情发生了一些变化,因为以前需要的依赖项 - ViewModelProviders
- got deprecated (有关详细信息,请参阅旧答案)。您现在可以直接使用ViewModelProvider
构造函数。
所以,在这种情况下,答案是:
private val viewModel = ViewModelProvider(this).get(SheduleViewModel::class.java)
但是,请注意,如果您包含 androidx.activity:activity-ktx:$Version
依赖项(一些常用的 AndroidX 依赖项已经为您包含了它),您可以使用属性委托:
private val viewModel: SheduleViewModel by viewModels()
在内部将使用ViewModelProvider
并将您的ViewModel
限定为您的Activity
。这只是写同一件事的更简洁的方式。您可以通过包含 androidx.fragment:fragment-ktx:$Version
依赖项来对 Fragment
执行相同的操作(同样,通常已包含在其他 AndroidX 依赖项中)。
ViewModelProvider
构造函数和by viewModels()
都接受工厂作为参数(用于注入ViewModel
):
private val viewModel =
ViewModelProvider(this, viewModelFactory).get(SheduleViewModel::class.java)
和
private val viewModel: SheduleViewModel by viewModels viewModelFactory
使用最适合您的。
旧答案:
添加androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion
依赖项以导入ViewModelProviders
。
【讨论】:
我导入了 viewmodelProviders。我可以看到它 如果您的代码符合您的编辑,则您缺少import androidx.lifecycle.ViewModelProviders
。它的末尾有一个 s。你需要import androidx.lifecycle.ViewModelProviders
和import androidx.lifecycle.ViewModelProvider
。
ViewModelProviders
已弃用,迁移到 ViewModelProvider
你能给出Java的语法吗
@Siva 几乎是一回事:SheduleViewModel viewModel = new ViewModelProvider(this).get(SheduleViewModel.class);
【参考方案2】:
将 ViewModel 更新到 Lifecycle Version 2.2.0 及以上
ViewModels(VM)理论上可以使用 Kotlin 扩展库 import androidx.fragment.app.viewModels
方法 by viewmodels()
初始化为类级实例变量。通过将 VM 初始化为类级别的实例 var,可以在类中访问它。
问题:将 VM 初始化为类级实例变量而不是在 onCreate
内部是否有缺点?
在使用onCreate
内的扩展函数创建 VM 时,VM 的范围仅在 onCreate
内,并且需要额外的代码来重新分配类级实例变量。
查看文档
ViewModel Overview Lifecycle将 VM 初始化为类实例 Val
class Fragment : Fragment()
private val viewModel: SomeViewModel by viewModels()
private fun observeViewState()
viewModel.feedViewState.observe(viewLifecycleOwner) viewState ->
//viewState used here.
在 onCreate 中初始化 VM 并重新分配类实例 Var
class Fragment : Fragment()
private lateinit var viewModel: SomeViewModel
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
val viewModel: ContentViewModel by viewModels()
this.viewModel = viewModel
private fun observeViewState()
viewModel.feedViewState.observe(viewLifecycleOwner) viewState ->
//viewState used here.
传递参数/参数
// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory()
override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
class SomeViewModel(private val someString: String) : ViewModel()
init
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
class Fragment: Fragment()
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels SomeViewModelFactory("someString")
使用参数/参数启用 SavedState
class SomeViewModelFactory(
private val owner: SavedStateRegistryOwner,
private val someString: String) : AbstractSavedStateViewModelFactory(owner, null)
override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
SomeViewModel(state, someString) as T
class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel()
val feedPosition = state.get<Int>(FEED_POSITION_KEY).let position ->
if (position == null) 0 else position
init
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
fun saveFeedPosition(position: Int)
state.set(FEED_POSITION_KEY, position)
class Fragment: Fragment()
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels SomeViewModelFactory(this, "someString")
private var feedPosition: Int = 0
override fun onSaveInstanceState(outState: Bundle)
super.onSaveInstanceState(outState)
someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
.findFirstVisibleItemPosition())
override fun onViewStateRestored(savedInstanceState: Bundle?)
super.onViewStateRestored(savedInstanceState)
feedPosition = someViewModel.feedPosition
【讨论】:
【参考方案3】:对我来说,唯一有效的是:
implementation 'androidx.fragment:fragment:1.2.4'
【讨论】:
【参考方案4】:附言。这适用于像我一样使用 java 并被卡住了一段时间的人,这个 SO 答案一直出现在谷歌中。
显然,API 自此日期(2020 年 5 月 6 日)起发生了变化,我必须这样做才能使其正常工作。
// 1. Create a ViewModel Class Let's call it AppStateViewModel
// 2. Put below code Inside Activity onCreate like this:
ViewModelProvider.Factory factory = new ViewModelProvider.NewInstanceFactory();
appStateManager = new ViewModelProvider(this, factory).get(AppStateViewModel.class);
【讨论】:
非常感谢!这就是我所缺少的,上面的大多数答案都需要更多时间来伪造。如果您使用最新的依赖项,这可能是您的答案。文档developer.android.com/topic/libraries/architecture/livedata 尚未更新以跟踪此评论时的 api 更改 非常感谢。这就是我一直在寻找的东西,但我在任何地方都找不到。都是 kotlin 或已弃用【参考方案5】:ViewModelProviders: 这个类已被弃用。直接使用 ViewModelProvider 的构造函数。
Kotlin
中的示例这是你可以直接使用ViewModelProvider的方法:
如果您的视图模型仅使用一个参数扩展 AndroidViewModel,应用程序 - 那么您可以使用默认的 AndroidViewModelFactory,而不必编写新的工厂。示例:
// Activity / fragment class
private lateinit var viewModel: MyOwnAndroidViewModel
// onCreate
viewModel = ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory(application)
).get(MyOwnAndroidViewModel::class.java)
如果您的视图模型只是扩展了 ViewModel 而没有额外的参数,那么请使用 NewInstanceFactory()。
// Activity / fragment class
private lateinit var viewModel: MyOwnViewModel
// onCreate
viewModel = ViewModelProvider(
this,
ViewModelProvider.NewInstanceFactory()
).get(MyOwnViewModel::class.java)
Adam 的上述回答也涵盖了其他变体。
免责声明:仍在学习基本的 Android 开发 - 如果代码有任何问题,请在 cmets 中告诉我。
【讨论】:
出于某种原因,我被要求使用 [MyOwnViewModel::class.java] 而不是 .get(MyOwnViewModel::class.java)【参考方案6】:(如何)使用 Android 架构组件中的ViewModel
:
添加 Google Maven 存储库(可选,只需验证)
默认情况下,Android Studio 项目未配置为访问此存储库。
要将其添加到您的项目中,请为您的项目打开 build.gradle
文件(不是您的应用或模块的文件)并添加 google()
存储库如下图:
allprojects
repositories
google()
jcenter()
声明依赖关系
打开您的应用级build.gradle
文件,
转到dependencies
块
AndroidX版本输入implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
,$lifecycle_version这里是最新版本定义。
对于 Pre-AndroidX 使用 implementation "android.arch.lifecycle:viewmodel:1.1.1"
(我猜 1.1.1 是这个工件的最后一个版本。)
在您的活动中,使用类似这样的语法
导入这个类:
import androidx.lifecycle.ViewModelProviders;
用于 AndroidX
import android.arch.lifecycle.ViewModelProviders;
使用 Pre-AndroidX
并获得您的ViewModel
,如下所示
ViewModelProviders.of(this).get(ProfileObservableViewModel::class.java)
// Kotlin 语法
----或----
ViewModelProviders.of(this).get(ProfileObservableViewModel.class);
// Java 语法
【讨论】:
乐于助人:)ViewModelProviders
在扩展中,请参阅 Ricardo Costeira 的回答。【参考方案7】:
在依赖项下的 app.gradle 中粘贴以下或类似内容(与您的设置相关)
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
【讨论】:
以上是关于如何在 AndroidX 中实例化 ViewModel?的主要内容,如果未能解决你的问题,请参考以下文章
无法实例化应用程序 androidx.multidex.MultiDexApplication:java.lang.ClassNotFoundException
Android 仪器化单元测试(instrumented unit tests) Androidx kotlin版本