如何为不同界面状态配置对应ViewModel并传递登录生成的Token?
推荐实现方案(完全符合Hilt和Android架构规范)
1. 实现全局Token存储单例
先创建全局的会话管理类,用Hilt标记为单例,统一管理登录态和Token,所有模块都可以注入调用:
@Singleton class AuthSession @Inject constructor() { // 用StateFlow存储Token,支持全局观察 private val _token = MutableStateFlow<String?>(null) val token: StateFlow<String?> = _token.asStateFlow() // 登录成功后调用更新Token fun saveToken(newToken: String) { _token.value = newToken // 可同步写入SharedPreferences实现登录态持久化 } // 退出登录时调用清空Token fun clearToken() { _token.value = null // 同步清空本地存储的登录信息 } }
AuthViewModel登录成功后直接调用authSession.saveToken(接口返回的Token)即可,不需要主动向其他业务模块传递Token。
2. 网络层自动注入Token
给OkHttp添加统一的请求拦截器,自动从AuthSession拿Token加到请求头,所有业务请求不需要单独处理Token逻辑:
@Singleton class AuthInterceptor @Inject constructor( private val authSession: AuthSession ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originRequest = chain.request() val token = authSession.token.value ?: return chain.proceed(originRequest) // 自动添加Authorization头 val authedRequest = originRequest.newBuilder() .addHeader("Authorization", "Bearer $token") .build() return chain.proceed(authedRequest) } }
把这个拦截器加到Hilt提供的OkHttpClient实例中,所有后端请求会自动携带登录态。
3. 路由逻辑优化
你原本的登录态控制路由逻辑可以直接保留,业务ViewModel不需要提前在Activity或者Scaffold中创建,在各自对应的业务页面用hiltViewModel()获取即可,完全符合Compose使用规范:
@ExperimentalComposeUiApi @Composable fun LoginState(vm: AuthViewModel = hiltViewModel(), nc: NavController) { val token by vm.token.collectAsState() when (token) { is Resource.Loading -> LoadingScreen() is Resource.Success -> { // 这里直接放主页面路由容器即可,子页面自行获取对应的ViewModel MainNavHost(navController = nc) } is Resource.Error -> LoginScreen(vm = vm) } }
比如用户页面需要UserViewModel,直接在UserPage Composable内写val userVm: UserViewModel = hiltViewModel()即可,Hilt会自动完成注入。
原方案问题说明
- 第一个方案的问题是误解了ViewModel的创建规则,不需要在Scaffold中统一创建所有ViewModel,每个业务页面单独获取自身所需的ViewModel就符合规范。
- 第二个ViewModelManager的方案属于强耦合反模式,后续新增业务ViewModel就要修改MainActivity和ViewModelManager代码,维护成本极高,完全不需要采用。
内容的提问来源于stack exchange,提问作者mama
相关产品推荐
相关产品推荐

