如何在 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.ViewModelProvidersimport 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版本

如何在flutter中使用flutter_webview_plugin和AndroidX

如何在 Qt 5 中使用带有实例化的 VAO

如何在Scala中实例化由类型参数表示的类型实例

如何在 Java 中实例化一组地图?