如何在Compose悬浮窗(AppOverlay)中使用HiltViewModel
解决方案:在Compose悬浮窗中使用Hilt注入ViewModel
默认的hiltViewModel()方法依赖ComponentActivity上下文来获取Hilt组件,而你的悬浮窗场景没有Activity,因此会抛出Expected an activity context异常。你不需要修改Hilt的HiltViewModelFactory,而是可以通过自定义ViewModel工厂结合Hilt的EntryPoint机制来实现注入。
步骤1:确保Hilt已初始化
首先确认你的Application类已添加@HiltAndroidApp注解,保证Hilt的全局组件正常工作:
@HiltAndroidApp class MyApp : Application()
步骤2:定义Hilt EntryPoint
创建一个EntryPoint来访问Hilt的SingletonComponent,用于后续创建ViewModel工厂:
@EntryPoint @InstallIn(SingletonComponent::class) interface SingletonComponentEntryPoint { fun singletonComponent(): SingletonComponent }
步骤3:自定义ViewModel工厂
实现一个基于Application级组件的ViewModel工厂,绕过对Activity的依赖:
class SingletonHiltViewModelFactory( private val application: Application, private val savedStateOwner: SavedStateRegistryOwner ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { // 获取Hilt的SingletonComponent val entryPoint = EntryPointAccessors.fromApplication( application, SingletonComponentEntryPoint::class.java ) // 使用HiltViewModelFactory结合全局组件创建ViewModel val hiltFactory = HiltViewModelFactory( application, savedStateOwner, entryPoint.singletonComponent() ) return hiltFactory.create(modelClass) } }
步骤4:在Composable中使用自定义工厂
替换原有的hiltViewModel()调用,改用自定义工厂创建ViewModel:
fun NavGraphBuilder.onBoardingGraph( navController: NavController, onboardingSave: () -> Unit ) { navigation(startDestination = Screen.Registration.route, route = OnBoardingNavGraphRoute) { composable(route = Screen.Registration.route) { navBackStackEntry -> val context = LocalContext.current val application = context.applicationContext as MyApp // 使用导航栈的BackStackEntry作为SavedStateOwner val factory = SingletonHiltViewModelFactory(application, navBackStackEntry) val viewModel: OnBoardingViewModel = ViewModelProvider(navBackStackEntry, factory)[OnBoardingViewModel::class.java] val uiState = viewModel.registrationScreenUiState.collectAsState() RegistrationScreen( onRegistrationDataSave = { navController.navigate(Screen.SeatSelection.route) } ) } composable(route = Screen.Login.route) { navBackStackEntry -> val context = LocalContext.current val application = context.applicationContext as MyApp val factory = SingletonHiltViewModelFactory(application, navBackStackEntry) val viewModel: OnBoardingViewModel = ViewModelProvider(navBackStackEntry, factory)[OnBoardingViewModel::class.java] val loginScreenUiState = viewModel.loginScreenUiState.collectAsState() LoginScreen(loginScreenUiState.value) } } }
关键说明
- 自定义工厂通过Hilt的EntryPoint获取全局的
SingletonComponent,避免了对Activity上下文的依赖。 - 使用导航栈的
NavBackStackEntry作为SavedStateRegistryOwner,保证ViewModel的状态能正确保存和恢复,和你之前用registerOwner的逻辑一致。 - 你的
OnBoardingViewModel仍需保留@HiltViewModel注解和@Inject构造函数,确保Hilt能正确注入依赖:
@HiltViewModel class OnBoardingViewModel @Inject constructor( // 你的依赖,比如Repository private val userRepository: UserRepository ) : ViewModel() { // ... ViewModel逻辑 }
内容的提问来源于stack exchange,提问作者vishnu ram
相关产品推荐
相关产品推荐

