My problem is that when using DataStore, the data is saved correctly and updated correctly every time, but it is read incorrectly. ( I open applicationB from applicationA and I am passing data with intent) When I launch the application for the first time, I do not have access to the data I wanted to transfer. Only when the application is relaunched, the data is returned from the DataStore, but it is old data.
This problem does not occur when using SharedPreferences.
I assume it's Dagger's fault because the DataStore and SharedPreferences write the data correctly, but the DataStore can't read it fast enough. DataStore is a relatively new library, so maybe this isn't handled correctly.
I've tried to restrict the scope so I've added @InstallIn(ViewModelComponent::class) but it didn't work. I've tried fetching the data about ipAdress in Application() class, but it didn't work either
Below is my RetrofitModule in which I try to get ipAddress from DataStore:
@Module
@InstallIn(SingletonComponent::class)
class RetrofitModule {
@Provides
@Singleton
fun provideNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
@Provides
@Singleton
fun provideRetrofitApi(
networkJson: Json,
dataStore: PreferencesDataSource
): RetrofitApi {
val refreshTokenInterceptor = createRefreshTokenInterceptor(dataStore)
return Retrofit.Builder()
.baseUrl(createUrl(dataStore))
.addConverterFactory(
networkJson.asConverterFactory("application/json".toMediaType())
)
.client(okHttpClient(refreshTokenInterceptor))
.build()
.create(RetrofitApi::class.java)
}
@Provides
@Singleton
fun providePlanogramApi(
networkJson: Json,
dataStore: PreferencesDataSource
): PlanogramApi {
val refreshTokenInterceptor = createRefreshTokenInterceptor(dataStore)
return Retrofit.Builder()
.baseUrl(BuildConfig.PLANOGRAM_BACKEND_URL)
.addConverterFactory(
networkJson.asConverterFactory("application/json".toMediaType())
)
.client(okHttpClient(refreshTokenInterceptor))
.build()
.create(PlanogramApi::class.java)
}
private fun okHttpClient(refreshTokenInterceptor: Interceptor): OkHttpClient {
return OkHttpClient().newBuilder()
.addInterceptor(refreshTokenInterceptor)
.addInterceptor(HttpLoggingInterceptor().apply {
if (shouldLog()) {
level = HttpLoggingInterceptor.Level.BODY
}
})
.build()
}
private fun createRefreshTokenInterceptor(dataStore: PreferencesDataSource): Interceptor {
return Interceptor { chain ->
val originalRequest = chain.request()
val refreshToken = runBlocking {
dataStore.userData.firstOrNull()?.token
}
val modifiedRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer $refreshToken")
.build()
chain.proceed(modifiedRequest)
}
}
private fun shouldLog(): Boolean {
return when (BuildConfig.FLAVOR) {
"prod" -> false
else -> true
}
}
private fun createUrl(dataStore: PreferencesDataSource): String {
val ipAddress = runBlocking {
dataStore.userData.firstOrNull()?.serverIp
}
return when (ipAddress) {
"" -> String.format(SERVER_URL_TEMPLATE, BuildConfig.BACKEND_URL)
else -> String.format(SERVER_URL_TEMPLATE, ipAddress)
}
}
companion object {
private const val SERVER_URL_TEMPLATE = "http://%s:1010"
}
}
DataStore Module:
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
@Provides
@Singleton
fun provideUserPreferencesSerializer() : UserPreferencesSerializer {
return UserPreferencesSerializer()
}
@Provides
@Singleton
fun provideUserPreferencesDataStore(
@ApplicationContext context: Context,
@Dispatcher(IO) ioDispatcher: CoroutineDispatcher,
@ApplicationScope scope: CoroutineScope,
userPreferencesSerializer: UserPreferencesSerializer,
) : DataStore<UserData> =
DataStoreFactory.create(
serializer = userPreferencesSerializer,
scope = CoroutineScope(scope.coroutineContext + ioDispatcher)
) {
context.dataStoreFile("user_preferences.json")
}
}