ViewModelProviders被弃用了,该怎么获取ViewModel?

本文分享了在使用Kotlin和Jetpack进行Android开发时,遇到ViewModelProviders弃用的问题及解决方案。作者通过研究androidx更新文档,找到了替代的ViewModelProvider使用方法。

首发于本人博客:keysking瞎写的东西
最近又有项目需要写安卓程序,决定使用Kotlin和Jetpack,但是在使用ViewModelProviders获取viewModel的时候却发现了问题.

ViewModelProviders被弃用了!

而且是在本文书写时的最新版本2.2.0被弃用的!因为刚刚弃用网上没发现几个相关讨论,甚至官网文档上还依旧是使用ViewModelProviders.

…强迫症之必须使用最新版本爆发,必须解决!

功夫不负有心人,在androidx的更新文档里找到了玄机(竟然还提供中文更新文档,太良心了)

所以,问题解决!

class MainActivity : AppCompatActivity() {
    private lateinit var myViewModel: MyViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        myViewModel = ViewModelProvider(this)[MyViewModel::class.java] // 关键代码
    }
}

<think> 首先,用户的问题是:"private val creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?> 这个东西是如何注入的"。这是在Android开发中,特别是在ViewModel工厂实现的上下文中的代码片段。 从上下文看,这似乎是关于Android的ViewModelProvider.Factory的实现。在之前的交互中,我解释了如何实现自定义的ViewModelProvider.Factory来处理SavedStateHandle。现在,用户指向了一个具体的代码部分:creators变量。 回顾知识:在Android的ViewModelProvider框架中,ViewModelProvider.Factory接口有一个create方法。但在一些高级实现或库中,比如Hilt或Dagger,可能会有映射来提供不同的ViewModel实例。creators看起来是一个映射,用于存储ViewModel类到其提供者的关系。 在用户提供的代码片段中:private val creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>。这类似于依赖注入框架如Dagger或Hilt中的设置。Provider<ViewModel?>? 表明这可能来自依赖注入容器。 如何注入的?意思是这个creators映射是如何被填充的。在依赖注入框架中: - 在Dagger或Hilt中,你可以定义一个模块或绑定来指定如何创建ViewModel实例。 - 通常,使用@Provides或@Binds方法来映射ViewModel类到其实例。 - 然后,在工厂实现中,通过注入一个映射到这个creators变量。 例如,在Hilt中,你可以有: - 使用@ViewModelInject或@AssistedInject来处理ViewModel的构造函数。 - 在自定义工厂中,Hilt会自动处理注入。 但在纯Android实现中,如果手动实现,creators可能需要手动初始化。然而,用户提到“注入”,所以可能是在DI框架上下文中。 在之前的回答中,我展示了一个自定义工厂,但没有使用映射。现在用户问这个如何注入,我应该解释这通常是依赖注入框架做的。 结构回答: 1. **解释代码含义**:creators是一个可变映射,键是ViewModel类的类型,值是一个Provider接口的实现(如来自javax.inject.Provider)。Provider对象负责创建ViewModel实例。 2. **注入方式**:在依赖注入框架中,如在Dagger或Hilt中: - 定义一个绑定:使用@Provides或@BindsInMap来创建映射。 - 然后在工厂类中,通过构造函数注入这个映射。 - 在create方法中,查找映射并调用provider来获取实例。 提供代码示例来澄清。 最后,必须添加§§相关问题§§部分,提出3-5个相关问题。问题要基于用户的问题和我的回答。 确保回答以中文输出。 完整结构: - 回答用户问题。 - 代码示例(如果有)。 - §§相关问题§§ 1. ... 2. ... 3. ... 4. ... 5. ... (确保不超过5个) 相关问题: 1. 在Hilt中如何为ViewModel提供自定义工厂? 2. Provider接口在依赖注入中的作用是什么? 3. 如何手动初始化creators映射而不使用DI框架? 4. ViewModel的生命周期与注入的关系? 5. 为什么使用映射而不是直接实例化? 现在,撰写回答。 </think> 在Android开发中,`private val creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>` 通常用于实现 `ViewModelProvider.Factory` 接口的工厂类中,其目的是通过依赖注入(DI)框架(如 Dagger Hilt)来动态提供 ViewModel 实例。这里的关键是 **依赖注入**:`creators` 映射本身是通过 DI 容器自动初始化和填充的,而非手动创建。以下是详细解释及 Kotlin 代码示例: ### 核心机制:注入原理 1. **映射结构**: - **键(Key)**:`Class<out ViewModel?>` - 表示 ViewModel 的类型(如 `MyViewModel::class.java`)。 - **值(Value)**:`Provider<ViewModel?>` - 一个提供 ViewModel 实例的接口(通常来自 `javax.inject.Provider` 或自定义实现),它封装了创建逻辑。 - **可变映射(MutableMap)**:允许运行时动态添加或移除绑定。 2. **注入方式**: - **使用依赖注入框架(如 Hilt)**: - 在 DI 模块中定义映射绑定(例如,使用 `@Binds` 或 `@IntoMap` 注解)。 - 工厂类的构造函数标记为 `@Inject`,框架会自动将填充好的映射注入到 `creators`。 - **手动注入(不使用框架)**: - 在工厂初始化时,手动将 ViewModel 类和其对应的 `Provider` 添加到映射中(较少用,因为 DI 更高效)。 ### 示例代码(使用 Dagger Hilt) 以下是一个完整实现,展示 `creators` 如何通过 Hilt 注入: ```kotlin // 步骤1:定义DI模块(Module)绑定映射 @Module @InstallIn(ViewModelComponent::class) abstract class ViewModelModule { @Binds @IntoMap @ViewModelKey(MyViewModel::class) // 自定义注解指定ViewModel类型 abstract fun bindMyViewModel(viewModel: MyViewModel): ViewModel } // 自定义注解用于映射键 @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @MapKey annotation class ViewModelKey(val value: KClass<out ViewModel>) // 步骤2:实现自定义Factory,注入creators映射 class MyViewModelFactory @Inject constructor( private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> // Hilt自动注入映射 ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T { // 从creators映射获取Provider val creator = creators[modelClass] ?: throw IllegalArgumentException("Unknown ViewModel class") // 通过Provider创建实例 return creator.get() as T } } // 步骤3:定义ViewModel类(Hilt处理构造函数注入) class MyViewModel @Inject constructor( private val repository: UserRepository // 依赖注入的Repository ) : ViewModel() { // ViewModel逻辑 } // 步骤4:在Activity中使用(Hilt自动处理) @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val viewModel: MyViewModel by viewModels() // Hilt注入工厂和ViewModel } ``` ### 关键说明 - **自动注入流程**: - Hilt 在编译时生成代码:扫描 `@ViewModelKey` 注解,将 `MyViewModel` 类与其 `Provider` 绑定到映射中。 - 当实例化 `MyViewModelFactory` 时,Hilt 自动将填充好的 `creators` 映射注入构造函数。 - **为何使用 `Provider`**:延迟实例化,确保 ViewModel 只在需要时创建(例如,当 `create()` 方法调用 `provider.get()`)。 - **安全性**:类型转换(`as T`)在 Hilt 绑定下是安全的,因为映射键确保匹配。 - **无 DI 框架的替代方案**:如果不用 Hilt,需手动初始化映射(如 `creators[MyViewModel::class.java] = Provider { MyViewModel(repository) }`),但维护成本高。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值