【问题标题】:how to instantiate ViewModel In AndroidX?如何在 AndroidX 中实例化 ViewModel?
【发布时间】: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

标签: android kotlin viewmodel android-jetpack kotlin-android-extensions


【解决方案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 内,并且需要额外的代码来重新分配类级实例变量。

查看文档

将 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

      1. 添加 Google Maven 存储库(可选,只需验证)

        默认情况下,Android Studio 项目未配置为访问此存储库。

        要将其添加到您的项目中,请为您的项目打开 build.gradle 文件(不是您的应用或模块的文件)并添加 google() 存储库如下图:

        allprojects {
            repositories {
                google()
                jcenter()
            }
        }
        
      2. 声明依赖关系

        打开您的应用级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 是这个工件的最后一个版本。)

      3. 在您的活动中,使用类似这样的语法

        导入这个类:

        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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-10
        相关资源
        最近更新 更多