如何在 AndroidX 中实例化 ViewModel?

how to instantiate ViewModel In AndroidX?

我想在 Activity 中使用 androidx 库

初始化 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中可能还有别的办法

更新的答案:

事情发生了一点变化,因为以前需要依赖 - 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.

(如何) 使用来自 Android 架构组件的 ViewModel :

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

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

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

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

    打开您的应用级 build.gradle 文件,

    转到dependencies{}

    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"换成AndroidX版本,$lifecycle_version这里是最新版本定义。

    对于 Pre-AndroidX 使用 implementation "android.arch.lifecycle:viewmodel:1.1.1" (我猜 1.1.1 是这个工件的最后一个版本。)

  3. 在你的activity中,像这样使用语法

    导入此 class:

    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 语法

正在将 ViewModel 更新到 Lifecycle Version 2.2.0 及更高版本

ViewModels (VM) 理论上可以使用 Kotlin 扩展库 import androidx.fragment.app.viewModels 方法 by viewmodels() 初始化为 class 级实例变量。通过将 VM 初始化为 class 级实例变量,可以在 class 中访问它。

问题:将 VM 初始化为 class 级实例变量而不是内部 onCreate 是否有缺点?

onCreate 中使用扩展函数创建 VM 时,VM 的作用域仅在 onCreate 内,并且需要额外的代码来重新分配 class 级别的实例变量。

查看文档

将 VM 初始化为 Class 实例值

class Fragment : Fragment() {
    private val viewModel: SomeViewModel by viewModels()

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}

在 onCreate 中初始化 VM 并重新分配 Class 实例 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.
        }
    }
}

通过 Arguments/Parameters

// 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") } 
}

使用 Arguments/Parameters

启用 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
    }
}

PS。这是给那些正在使用 java 并且像我一样卡住了一段时间的人,这个 SO 答案一直出现在 google 中。

显然,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);

ViewModelProviders: This class is deprecated. Use the constructors for ViewModelProvider directly.

Kotlin

中的示例

这是您可以直接使用 ViewModelProvider 的方式:

如果您的视图模型正在扩展 AndroidViewModel with just one argument, the app - then you can use the default AndroidViewModelFactory 并且您不必编写新工厂。示例:

// Activity / fragment class
private lateinit var viewModel: MyOwnAndroidViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory(application)
        ).get(MyOwnAndroidViewModel::class.java)

如果您的视图模型仅扩展 ViewModel without extra arguments then use the NewInstanceFactory()

// Activity / fragment class
private lateinit var viewModel: MyOwnViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.NewInstanceFactory()
        ).get(MyOwnViewModel::class.java)

上面亚当的回答也涵盖了其他变体。

免责声明:仍在学习基础 Android 开发 - 如果代码有任何问题,请在评论中告诉我。

对我来说,唯一有效的方法是:

implementation 'androidx.fragment:fragment:1.2.4'

在 app.gradle 下的 dependencies

中粘贴以下或类似内容(与您的设置相关)
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'

将下面的代码粘贴到 build.gradle(:app)

implementation 'androidx.fragment:fragment-ktx:1.4.1'

在您的应用 gradle 文件中,确保您已添加以下依赖项:

Activity 使用:

implementation "androidx.activity:activity-ktx:1.4.1"

片段使用:

implementation 'androidx.fragment:fragment:1.4.1'

我添加了这个依赖的最后一个版本 https://developer.android.com/kotlin/ktx/extensions-list

实施“androidx.activity:activity-ktx:1.4.0”