androidkotlinandroid-jetpack-datastore

Global DataStore instance. Kotlin


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
    }


Solution

  • In order to use DataStore safely, use a dependency injection framework like Hilt or Koin. This would also promote better code organization by limiting unnecessary exposure of the DataStore.

    Below I shared how you can use Hilt to be able to provide DataStore as a Singleton object.

    @Module
    @InstallIn(SingletonComponent::class)
    class DataStoreModule {
    
        @Singleton
        @Provides
        fun provideDataStore(application: Application): DataStore { 
            return DataStore(application.applicationContext)
        }
    }
    

    This would allow you to inject DataStore like this:

    @HiltViewModel
    class MyViewModel @Inject constructor(
        private val dataStore: DataStore
    ) : ViewModel() {
    
        fun useToken() {
            viewModelScope.launch { 
                val token = dataStore.getToken()
            }
        }
    }
    

    If you're not familiar with Hilt i recommend you check this out: https://developer.android.com/training/dependency-injection/hilt-android

    For Koin: https://insert-koin.io/docs/quickstart/android/