Kotlin DataStore全局单例内存泄漏,求正确实现方式
解决DataStore全局实例的内存泄漏问题
你遇到的StaticFieldLeak警告,原因是伴生对象中的静态变量持有了Application实例的强引用,静态变量的生命周期和整个应用进程绑定,当Application因配置变更等原因被销毁时,这个引用会导致旧的Application实例无法被垃圾回收,从而引发内存泄漏。
下面是几种正确的实现方式:
方式一:使用Hilt依赖注入(推荐)
依赖注入框架能自动管理对象生命周期,避免手动管理单例带来的内存泄漏问题。
- 配置Hilt并修改Application类
@HiltAndroidApp class MyApplication : Application()
- 创建Module提供DataStore单例
@Module @InstallIn(SingletonComponent::class) object DataStoreModule { @Provides fun provideTokenDataStore(@ApplicationContext context: Context): DataStoreManager { return TokenDataStore(context) } }
- 在需要使用的地方注入
class SomeViewModel @Inject constructor( private val dataStoreManager: DataStoreManager ) : ViewModel() { // 调用dataStoreManager的getToken/saveToken/clearToken方法 }
方式二:手动实现安全的懒加载单例
如果不使用依赖注入,需要确保单例持有Application Context而非Activity/Application实例本身,同时用双重校验锁保证线程安全。
首先修改DataStore类(建议重命名避免和Jetpack的DataStore类冲突):
interface DataStoreManager { suspend fun getToken(): String suspend fun saveToken(token: String) suspend fun clearToken() } class TokenDataStore private constructor(private val context: Context) : DataStoreManager { private val Context.dataStore by preferencesDataStore(name = "settings") override suspend fun getToken(): String = withContext(Dispatchers.IO) { val preferences = context.dataStore.data.first() preferences[PreferencesKeys.TOKEN] ?: "" } override suspend fun saveToken(token: String) = withContext(Dispatchers.IO) { context.dataStore.edit { it[PreferencesKeys.TOKEN] = token } } override suspend fun clearToken() = withContext(Dispatchers.IO) { context.dataStore.edit { it.remove(PreferencesKeys.TOKEN) } } private object PreferencesKeys { val TOKEN = stringPreferencesKey("access_token") } companion object { @Volatile private var INSTANCE: TokenDataStore? = null fun getInstance(context: Context): TokenDataStore { return INSTANCE ?: synchronized(this) { // 使用applicationContext避免持有具体组件实例 val instance = TokenDataStore(context.applicationContext) INSTANCE = instance instance } } } }
然后在需要使用的地方获取实例:
// 在Activity/Fragment中 val dataStoreManager = TokenDataStore.getInstance(this) // 在Application的onCreate中提前初始化(可选) class MyApplication : Application() { override fun onCreate() { super.onCreate() TokenDataStore.getInstance(this) } }
为什么原代码会触发警告?
原代码中MyApplication伴生对象的dataStore变量是静态的,它持有了MyApplication的实例引用。静态变量的生命周期和应用进程一致,当Application因配置变更(如屏幕旋转)被销毁重建时,旧的Application实例会被这个静态引用卡住,无法被GC回收,最终导致内存泄漏。
内容的提问来源于stack exchange,提问作者nero-123
相关产品推荐
相关产品推荐

