I want to store an access token in the DataStore when it is received. As such i created a class(DataStore) that handles the getting,saving and clearing. Since I want the same instance of DataStore to be available everywhere, I instantiated it in the MainApplication. My thinking was that all other classes will be able to access it with MyApplication.dataStore.
I am however getting a memory leak warning from the IDE. What is the advised way to do this?
thank you
class MyApplication : Application() {
companion object {
lateinit var dataStore: DataStore // memory leak warning here. StaticFieldLeak
}
private var tokenRetrievalScope: CoroutineScope? = null
override fun onCreate() {
super.onCreate()
dataStore= DataStore(context = this)
}
}
interface DataStoreManager {
suspend fun getToken(): String
suspend fun saveToken(token: String)
suspend fun clearToken() // Function to clear the token if needed
}
class DataStore(private val context: Context) : DataStoreManager {
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
override suspend fun getToken(): String = withContext(Dispatchers.IO) {
val preferences = context.dataStore.data.first() // Fetch Preferences
preferences[PreferencesKeys.TOKEN] ?: "" // Access token with default
}
The companion object of a class exists even when there is no instance of that class around. In that regard it is similar to static fields in Java. There is no regular way to clean that up. That is especially problematic when context objects are stored this way because they prevent their associated objects (activities, services, etc.) from being removed from memory when they are not needed aymore. In your case, however, the context is the application context. Since that will never need to be cleaned up as long as your app runs, this entire problem scenario doesn't apply. The compiler, however, just detects that some context is stored in a companion object and warns you of a memory leak, without realizing that it is just the (unproblematic) application context.
You can therefore safely ignore the compiler warning.
You can avoid this entire situation, though, if you use a dependency injection framework. That way you don't instantiate the objects you need yourself, you let the DI framework inject them to where they are needed. You can annotate a class with
@Singletonso that the same instance is shared everywhere. If you use Hilt for dependency injection on android, you can also easily retrieve the application context that you need for your data store:Now, everytime you get a DataStore object injected, it will always be the same instance.