Reputation: 167
I have an interface called LoginService which is used with Retrofit. There was no accessToken before the user login. When the user has logged in, the LoginService Instance should be updated with acessToken so that the user could log out from the app. The problem is that LoginService class is not updated even though it is not declared as @Singleton. If the user has closed the app and reopen it again, the LoginService got updated and therefore he could log out of the app. How can I reinitialize the LoginService instance as soon as the accessToken has been updated?
Upvotes: 1
Views: 656
Reputation: 1633
The key here is not the reinitialize the instance but to create a separate service whenever the user logs in.
you need to have two different interfaces one for API's pre-login and other for post login.
So one would be Authapi.kt
and the other would be Api.kt
So first we need to create OkHttpBuilder for each service,
@Provides
@Singleton
@Named(NetModule.NO_AUTH_CLIENT)
fun provideNoAuthOkHttpClient(
okHttpClientBuilder: OkHttpClient.Builder
): OkHttpClient {
return okHttpClientBuilder.build()
}
@Provides
@Singleton
@Named(NetModule.AUTH_CLIENT)
fun provideAuthOkHttpClient(
okHttpClientBuilder: OkHttpClient.Builder,
tokenInterceptor: NetworkInterceptor
): OkHttpClient {
return okHttpClientBuilder.addInterceptor(tokenInterceptor).build()
}
Network Interceptor is the class where you update your access token for API.
NetworkInterceptor.kt
class NetworkInterceptor @Inject constructor(
val context: Context,
serverBaseUrl: String,
val moshi: Moshi,
val preferences: PreferenceUtility
) : Interceptor {
private fun Request.Builder.setDefaultHeaders(): Request.Builder {
addHeader("App_version_code", BuildConfig.VERSION_CODE.toString())
addHeader("App_version_name", BuildConfig.VERSION_NAME)
addHeader("Mobile_model", Build.MODEL.toString())
addHeader("OS_version", Build.VERSION.SDK_INT.toString())
addHeader("OS_version_release", Build.VERSION.RELEASE.toString())
if (preferences.customerId != -1L)
addHeader("Client_id", preferences.customerId.toString())
return this
}
private fun makeRequestWithAuthTokenAndTimeStamp(request: Request) = request.newBuilder()
.setDefaultHeaders()
.apply {
val oldHeader = request.header("Authorization")
if (oldHeader.isNullOrBlank()) {
val token = if (preferences.authToken.isBlank() || !preferences.customerAuthenticated) BuildConfig.ANONYMOUS_TOKEN else preferences.authToken
addHeader("Authorization", "Bearer $token")
}
}
.url(request.url())
.method(request.method(), request.body())
.build()
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// ADD THE TOKEN'S OVER HERE
var response =
chain.proceed(makeRequestWithAuthTokenAndTimeStamp(request))
//You can also add refersh logic here.
return response
}
}
And you NetworkModule.kt will be
@Provides
@Singleton
@Named(NetModule.NO_AUTH_CLIENT)
fun provideNoAuthInterceptorRetrofit(
moshi: Moshi,
@Named(NetModule.NO_AUTH_CLIENT) okHttpClient: OkHttpClient,
debugPreferenceUtility: DebugPreferenceUtility
): Retrofit {
return Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(debugPreferenceUtility.serverBaseUrl)
.client(okHttpClient)
.build()
}
@Provides
@Singleton
@Named(NetModule.AUTH_CLIENT)
fun provideAuthInterceptorRetrofit(
moshi: Moshi,
@Named(NetModule.AUTH_CLIENT) okHttpClient: OkHttpClient,
debugPreferenceUtility: DebugPreferenceUtility
): Retrofit {
return Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(debugPreferenceUtility.serverBaseUrl)
.client(okHttpClient)
.build()
}
@Provides
@Singleton
fun provideApi(@Named(AUTH_CLIENT) retrofit: Retrofit) = retrofit.create(Api::class.java)
@Provides
@Singleton
fun provideAuthApi(@Named(NO_AUTH_CLIENT) retrofit: Retrofit) = retrofit.create(AuthApi::class.java)
So the API's that will be used pre-login will be placed inside AuthApi.kt
like send OTP etc and all the rest API will be placed inside Api.kt
and Network Interceptor will take care of adding token.
Upvotes: 1