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

Android:正确使用ViewModelProvider.Factory初始化带依赖的ViewModel

不用DI框架实现ViewModel的依赖注入(遵循控制反转)

核心思路

把依赖的初始化移到Application或Activity这类生命周期稳定的组件中,通过自定义ViewModelProvider.Factory将依赖传入ViewModel,避免在Composable中直接创建依赖和ViewModel,解决context失效、重复创建的问题。

步骤1:定义依赖类(以SettingsDataStore为例)

依赖类需要context时,使用Application级别的context(生命周期与App一致,不会失效):

class SettingsDataStore(private val appContext: Context) {
    // 实现你的DataStore逻辑,比如读取/存储设置
    val darkModeFlow = appContext.dataStore.data.map { preferences ->
        preferences[SettingsKeys.DARK_MODE] ?: false
    }
}

步骤2:自定义ViewModelFactory

创建工厂类,接收ViewModel所需的所有依赖,在create方法中实例化ViewModel:

class NewsViewModelFactory(
    private val settingsDataStore: SettingsDataStore,
    private val newsRepository: NewsRepository // 示例其他依赖
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        // 校验ViewModel类型,避免创建错误实例
        if (modelClass.isAssignableFrom(NewsViewModel::class.java)) {
            return NewsViewModel(settingsDataStore, newsRepository) as T
        }
        throw IllegalArgumentException("无法识别的ViewModel类: ${modelClass.name}")
    }
}

步骤3:在全局组件中初始化依赖

推荐在Application中初始化全局依赖,确保整个App生命周期内仅创建一次:

class MyApplication : Application() {
    // 全局依赖实例
    lateinit var settingsDataStore: SettingsDataStore
    lateinit var newsRepository: NewsRepository

    override fun onCreate() {
        super.onCreate()
        // 用Application的context初始化DataStore
        settingsDataStore = SettingsDataStore(this)
        // 如果Repository依赖DataStore,直接传入
        newsRepository = NewsRepository(settingsDataStore)
    }
}

记得在AndroidManifest.xml中注册这个Application:

<application
    android:name=".MyApplication"
    ...>
    ...
</application>

步骤4:在Composable中获取ViewModel

通过viewModel()方法传入自定义Factory,ViewModel会被Jetpack生命周期管理,不会重复创建:

@Composable
fun NewsScreen() {
    // 获取Application实例,拿到全局依赖
    val app = LocalContext.current.applicationContext as MyApplication
    val viewModel = viewModel<NewsViewModel>(
        factory = NewsViewModelFactory(
            app.settingsDataStore,
            app.newsRepository
        )
    )

    // 后续UI逻辑,比如观察ViewModel的数据
    val darkMode by viewModel.darkMode.collectAsStateWithLifecycle()
    ...
}

替代方案:在Activity中初始化依赖

如果依赖仅在某个Activity范围内使用,可以在Activity中初始化,再传给Composable:

class NewsActivity : ComponentActivity() {
    private lateinit var settingsDataStore: SettingsDataStore
    private lateinit var newsRepository: NewsRepository

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        settingsDataStore = SettingsDataStore(applicationContext)
        newsRepository = NewsRepository(settingsDataStore)
        setContent {
            MyAppTheme {
                NewsScreen(
                    factory = NewsViewModelFactory(settingsDataStore, newsRepository)
                )
            }
        }
    }
}

@Composable
fun NewsScreen(factory: NewsViewModelFactory) {
    val viewModel = viewModel<NewsViewModel>(factory = factory)
    ...
}

关键优势

  • 避免context失效:依赖使用Application或Activity的context,生命周期稳定
  • 防止重复创建:ViewModel由Jetpack的ViewModelProvider管理,与LifecycleOwner绑定,不会因Composable重组重复实例化
  • 遵循控制反转:ViewModel不负责创建依赖,仅接收外部传入的实例,符合单一职责原则

内容的提问来源于stack exchange,提问作者Josip Domazet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:52:45