Я внедряю модифицированные экземпляры с помощью 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(), но эта функция возвращает поток данных, которые являются функцией приостановки, которую нельзя вызвать из функции. Любая помощь будет оценена по достоинству.
Вы можете использовать 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)
})
@AkritKhanna Каждая функция Kotlin имеет возвращаемый тип. Функции «без возвращаемого типа» на самом деле возвращают Unit
.
Ок, но я пытаюсь заблокировать поток с помощью функции Unit, но она не работает.
Это сработало. Я хочу задать еще один вопрос, можем ли мы выполнить функцию приостановки без возвращаемого типа внутри runBlocking {...} ?