Доступ к настройкам DataStore в клиенте Retrofit [HILT]

Я внедряю модифицированные экземпляры с помощью HILT, теперь моя проблема заключается в том, что я хочу добавить токен авторизации в запрос, который хранится в настройках хранилища данных. Я новичок в сопрограммах и рукояти, поэтому я не понимаю, как сделать то же самое. Раньше я получал токен, используя общие настройки, что было довольно просто.

AppModule.kt

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    fun provideRetrofit(@ApplicationContext context: Context, sessionManager: SessionManager): Retrofit {

        //sessionManager.getToken() cannot call this as it requires provideRetrofit() to be a suspend function 

        val builder = OkHttpClient.Builder()
        //This is to check the logs of api request
        val logging = HttpLoggingInterceptor()
        logging.setLevel(HttpLoggingInterceptor.Level.BODY)

        builder.writeTimeout(60, TimeUnit.SECONDS)
        builder.readTimeout(60, TimeUnit.SECONDS)
        builder.connectTimeout(60, TimeUnit.SECONDS)

        //create network interceptor

        //create network interceptor

        Log.d("TAG", "provideRetrofit: $token")

        builder.addNetworkInterceptor(Interceptor { chain: Interceptor.Chain ->
            val request = chain.request()
            chain.proceed(request).newBuilder()
                .header("Cache-Control", "public")
                .removeHeader("Pragma")
                .build()
        })

        //create offline interceptor


        builder.addInterceptor(Interceptor { chain: Interceptor.Chain ->
            var request = chain.request()

            if (!Tools.checkInternet(context)) {
                val maxStale = 60 * 60 * 24 * 30 // Offline cache available for 30 days
                request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
                    .removeHeader("Pragma")
                    .build()
            }
            chain.proceed(request)
        })

        builder.addInterceptor(logging)

        //setup cache


        //setup cache
        val httpCacheDirectory: File = File(context.getCacheDir(), "responses")
        val cacheSize = 10 * 1024 * 1024 // 10 MB

        val cache = Cache(httpCacheDirectory, cacheSize.toLong())

        builder.cache(cache)


        return Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(builder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    fun provideApi(retrofit: Retrofit): ApiInterface = retrofit.create(ApiInterface::class.java)

    @Provides
    @Singleton
    fun provideSessionManager(@ApplicationContext context: Context) = SessionManager(context)

}

SessionManager.kt

class SessionManager @Inject constructor(@ApplicationContext private val context: Context) {

    private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = Constants.PREFERENCES)


    private val tokenPreferences = stringPreferencesKey(Constants.AUTH_TOKEN)

    suspend fun saveToken(token : String){

        context.dataStore.edit {
            it[tokenPreferences] = token
        }
    }

    fun getToken() = context.dataStore.data.map {
        it[tokenPreferences]
    }
}

Я хочу получить значение токена с помощью функции getToken(), но эта функция возвращает поток данных, которые являются функцией приостановки, которую нельзя вызвать из функции. Любая помощь будет оценена по достоинству.

0
0
41
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать runBlocking для запуска функции приостановки из обычной функции. Перехватчики OkHttp работают в пуле потоков, а не в основном потоке, поэтому получение там текущего токена должно быть безопасным.

        builder.addNetworkInterceptor(Interceptor { chain: Interceptor.Chain ->
            val token = runBlocking {
                sessionManager.getToken().first()
            }
            val request = chain.request().newBuilder()
                .addHeader("Authorization", "Bearer $token")
                .build()
            chain.proceed(request)
        })

Это сработало. Я хочу задать еще один вопрос, можем ли мы выполнить функцию приостановки без возвращаемого типа внутри runBlocking {...} ?

Akrit Khanna 23.03.2022 07:32

@AkritKhanna Каждая функция Kotlin имеет возвращаемый тип. Функции «без возвращаемого типа» на самом деле возвращают Unit.

Nitrodon 23.03.2022 14:49

Ок, но я пытаюсь заблокировать поток с помощью функции Unit, но она не работает.

Akrit Khanna 23.03.2022 16:51

Другие вопросы по теме