Issue fetching data from DataStore, but using Shared preferences everything works

42 Views Asked by At

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")
        }
}
0

There are 0 best solutions below