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

Hilt注入全局单例仓库问题:ViewModel重建后_user为空

排查思路与解决方案

嘿,我来帮你拆解这个问题~首先你已经通过调试确认注入的UserRepository是同一实例,那Hilt的单例注入逻辑肯定没问题,问题出在这个单例实例的_user状态丢失上,我们从几个核心方向排查:

1. 优先确认:App进程是否被系统销毁重建

这是Android开发中全局状态丢失最常见的原因:

  • 当App处于后台且系统内存不足时,系统会主动杀死进程;等你回到App时,Application会重新初始化,Hilt的ApplicationComponent里的所有单例(包括你的UserRepository)都会被全新创建,这时候_user自然回到初始的null状态。
  • 验证方法:给UserRepository的构造函数加日志追踪实例创建:
    @Singleton class UserRepository @Inject constructor() : UserService {
        init {
            Log.d("UserRepoDebug", "新的Repository实例创建:${this.hashCode()}")
        }
        // ... 原有代码
    }
    
    测试步骤:把App切到后台,用开发者选项的「终止应用」手动杀死进程,再重新打开App,查看日志是否打印了新的哈希值。如果是,那就是进程重建导致的状态丢失。
  • 解决办法:把_user的状态持久化,比如用DataStore、SharedPreferences或者Room数据库,在getUser()时先从存储读取,fetchUser()成功后写入存储。

2. 检查是否有隐藏逻辑修改了_user为null

虽然你贴的代码里没有,但实际项目中可能存在你没注意到的逻辑:

  • 比如有没有logout()方法会执行_user = null?或者其他业务模块不小心修改了这个字段?
  • 验证方法:给_user字段加监听日志,追踪它的修改轨迹:
    @Volatile private var _user: User? = null
        set(value) {
            field = value
            Log.d("UserRepoDebug", "_user被更新为:${value?.name ?: "null"}")
        }
    
    这样就能精准定位_user什么时候被置为null了。

3. 排查线程安全问题

你的getUser()和fetchUser()没有做线程同步,可能存在并发访问导致的状态异常:

  • 比如在fetchUser()的2秒延迟期间,多次调用getUser()会触发重复请求,虽然正常情况下最终_user会被赋值,但如果某个请求出现异常(比如RxJava的错误回调),会不会间接导致_user被置空?
  • 优化方案:用RxJava的ReplaySubject缓存用户数据,避免重复请求并保证线程安全:
    private val userCache: ReplaySubject<User> = ReplaySubject.createWithSize(1)
    
    override fun getUser(): Observable<User> {
        return if (_user == null) {
            fetchUser().doOnNext {
                _user = it
                userCache.onNext(it)
            }
        } else {
            userCache
        }
    }
    

4. 确认ViewModel的重建场景

ViewModel虽然能跨配置变更(比如旋转屏幕)存活,但如果是进程被杀后重建,ViewModel会被重新创建,同时注入的UserRepository也是全新实例(因为Application重建了)。这种情况下,ViewModel的SavedStateHandle只能保存自身的状态,全局的用户数据还是得靠持久化存储来留存。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:17:56