Android单例SessionManager如何处理进程死亡致令牌丢失问题
问题根因
SessionManager单例的生命周期和应用进程完全绑定,不管是应用崩溃、系统后台回收进程还是用户手动杀应用,整个进程的内存空间都会被完全回收,内存中存储的MutableLiveData实例、持有的AuthToken数据、甚至单例对象本身都会被销毁。下次启动应用是全新的进程实例,自然读不到之前内存里的令牌数据,这和LiveData本身的实现无关,核心问题是认证令牌只做了内存存储,没有持久化到本地。
处理方案
- 令牌持久化:拿到有效
AuthToken(登录成功、刷新令牌成功)时,除了更新内存中的LiveData,必须同步将令牌加密后持久化到本地。你已经注入了CacheManager,直接基于它实现存储即可,敏感认证令牌优先使用加密存储方案(如EncryptedSharedPreferences),不要明文存储避免泄漏。 - 启动态恢复:给
SessionManager增加初始化入口,在应用启动、进程创建完成的第一时间(比如Application的onCreate中),从本地持久化层读取之前存储的有效令牌,读取成功后直接更新到_sessionState中,完成登录态恢复。 - 状态一致性处理:登出、令牌过期失效时,要同步清除本地持久化的令牌数据,再更新LiveData为未登录状态,避免本地残留脏数据。
- 有效期校验:从本地读取缓存令牌时,必须先校验令牌是否过期,过期令牌直接清除,不要返回给业务层使用,避免无效请求。
改造后参考实现
@Singleton class SessionManager @Inject constructor( private val sessionRepository: SessionRepository, private val cacheManager: CacheManager ) { private val sessionScope = CoroutineScope(Dispatchers.Main.immediate) private val _sessionState = MutableLiveData<Resource<AuthToken>>() val sessionState: LiveData<Resource<AuthToken>> get() = _sessionState /** * 应用启动时调用,恢复本地持久化的登录态 */ fun init() { sessionScope.launch { val cachedToken = cacheManager.get<AuthToken>(KEY_AUTH_TOKEN) when { cachedToken != null && !cachedToken.isExpired() -> { _sessionState.value = Resource.Success(cachedToken) } else -> { cacheManager.remove(KEY_AUTH_TOKEN) _sessionState.value = Resource.Error("未登录") } } } } /** * 登录成功、令牌刷新成功后调用,更新状态并持久化 */ fun updateAuthToken(token: AuthToken) { sessionScope.launch { cacheManager.put(KEY_AUTH_TOKEN, token) _sessionState.value = Resource.Success(token) } } /** * 登出、令牌失效时调用,清除内存和本地缓存 */ fun clearSession() { sessionScope.launch { cacheManager.remove(KEY_AUTH_TOKEN) _sessionState.value = Resource.Error("会话已失效") } } private companion object { const val KEY_AUTH_TOKEN = "sp_key_auth_token" } }
注意:不要尝试通过静态变量持有、进程保活等内存层面的方案解决该问题,只要进程被系统回收,内存数据必然丢失,本地持久化是唯一可靠的解决路径。
内容的提问来源于stack exchange,提问作者Andyson
相关产品推荐
相关产品推荐

