You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android ViewModel构造函数调用时机及含SavedStateHandle的多参数如何传入工厂?

问题解答

1. ViewModel构造函数的调用时机

  • 首次调用ViewModelProvider.get(SavedStateViewModel.class)获取对应ViewModel实例时,构造函数会被触发执行
  • 同一个ViewModelStoreOwner(如对应的Activity/Fragment)的生命周期内,重复调用get方法不会重复执行构造函数,会直接返回已缓存的实例
  • 仅当ViewModelStoreOwner彻底销毁(如Activity正常finish、Fragment被正式移除)后,下次重新创建该Owner时调用get方法,才会再次触发构造函数执行,配置变更(如屏幕旋转)不会触发构造函数重新执行。

2. SavedStateHandle参数的获取逻辑

你示例中不需要手动传参就能拿到SavedStateHandle实例,是因为ViewModelProvider默认使用SavedStateViewModelFactory来实例化ViewModel,该工厂会自动完成以下流程:

  1. 读取当前Activity的Intent extras或Fragment的arguments作为初始数据
  2. 封装生成对应的SavedStateHandle实例
  3. 匹配ViewModel构造函数的参数类型,检测到需要SavedStateHandle参数时自动注入该实例,不需要开发者手动传入。

3. 混合Hilt依赖、运行时参数、SavedStateHandle的实现示例

如果你的ViewModel需要同时传入Hilt注入的依赖、运行时动态参数、SavedStateHandle,推荐使用Hilt的辅助注入功能实现,示例如下:

第一步:定义ViewModel,声明辅助注入

import androidx.lifecycle.ViewModel
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject

// 声明辅助工厂交给Hilt生成实现
@HiltViewModel(assistedFactory = MyViewModel.Factory::class)
class MyViewModel @AssistedInject constructor(
    // 由Hilt自动注入的依赖,无需加@Assisted注解
    private val userRepository: UserRepository,
    private val postRepository: PostRepository,
    // 运行时传入的动态参数,加@Assisted注解
    @Assisted private val categoryId: Int,
    // 用于进程恢复的SavedStateHandle,加@Assisted注解
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    // 定义辅助工厂接口
    interface Factory {
        fun create(categoryId: Int, savedStateHandle: SavedStateHandle): MyViewModel
    }

    // 此处编写ViewModel的业务逻辑
}

第二步:在Activity/Fragment中实例化ViewModel

import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class DemoActivity : AppCompatActivity() {
    // 从Intent中获取运行时参数:分类ID
    private val categoryId by lazy { intent.getIntExtra("KEY_CATEGORY_ID", 0) }

    // 实例化ViewModel
    private val viewModel: MyViewModel by viewModels {
        SavedStateViewModelFactory(application, this, intent.extras).create(
            key = null,
            modelClass = MyViewModel::class.java
        )
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 直接使用viewModel即可
    }
}

如果不想用Hilt辅助注入,也可以自定义继承AbstractSavedStateViewModelFactory的工厂类实现,示例如下:

import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.savedstate.SavedStateRegistryOwner

class CustomViewModelFactory(
    private val userRepository: UserRepository,
    private val categoryId: Int,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
    override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
        @Suppress("UNCHECKED_CAST")
        return MyViewModel(userRepository, categoryId, handle) as T
    }
}

在Activity中使用自定义工厂:

@AndroidEntryPoint
class DemoActivity : AppCompatActivity() {
    // 注入Hilt管理的Repository实例
    @Inject lateinit var userRepository: UserRepository

    private val categoryId by lazy { intent.getIntExtra("KEY_CATEGORY_ID", 0) }

    private val viewModel: MyViewModel by viewModels {
        CustomViewModelFactory(userRepository, categoryId, this, intent.extras)
    }
}

内容的提问来源于stack exchange,提问作者Neeraja Gandla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 07:06:03