在 Retrofit 客户端 [HILT] 中访问 DataStore 首选项

Accessing DataStore Preferences inside Retrofit client [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() 函数获取令牌的值,但是这个函数 returns flow 的数据是暂停函数,不能从功能。任何形式的帮助将不胜感激。

您可以使用 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)
        })