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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:55:54