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
相关产品推荐
相关产品推荐

