'Accessing sharedPreferences inside Retrofit Interceptor
Here is a Retrofit Interceptor used to inject automatically a token inside requests. I'm trying to get this token from sharedPreferences but getSharedPreferences is not available there.
How can i retrieve my token from sharedpreferences inside this Interceptor ?
import android.preference.PreferenceManager
import okhttp3.Interceptor
import okhttp3.Response
class ServiceInterceptor: Interceptor {
var token : String = "";
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
if(request.header("No-Authentication") == null){
if (request.url.toString().contains("/user/signin") === false) {
// Add Authorization header only if it's not the user signin request.
// Get token from shared preferences
val sharedPreference = PreferenceManager.getSharedPreferences()
token = sharedPreference.getString("token")
if (!token.isNullOrEmpty()) {
val finalToken = "Bearer " + token
request = request.newBuilder()
.addHeader("Authorization", finalToken)
.build()
}
}
}
return chain.proceed(request)
}
}
Solution 1:[1]
There's a simple solution for this in Kotlin – just copy & paste the code into a new AppPreferences.kt file and follow the 4 TODO steps outlined in the code:
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import androidx.core.content.edit
object AppPreferences {
private var sharedPreferences: SharedPreferences? = null
// TODO step 1: call `AppPreferences.setup(applicationContext)` in your MainActivity's `onCreate` method
fun setup(context: Context) {
// TODO step 2: set your app name here
sharedPreferences = context.getSharedPreferences("<YOUR_APP_NAME>.sharedprefs", MODE_PRIVATE)
}
// TODO step 4: replace these example attributes with your stored values
var heightInCentimeters: Int?
get() = Key.HEIGHT.getInt()
set(value) = Key.HEIGHT.setInt(value)
var birthdayInMilliseconds: Long?
get() = Key.BIRTHDAY.getLong()
set(value) = Key.BIRTHDAY.setLong(value)
private enum class Key {
HEIGHT, BIRTHDAY; // TODO step 3: replace these cases with your stored values keys
fun getBoolean(): Boolean? = if (sharedPreferences!!.contains(name)) sharedPreferences!!.getBoolean(name, false) else null
fun getFloat(): Float? = if (sharedPreferences!!.contains(name)) sharedPreferences!!.getFloat(name, 0f) else null
fun getInt(): Int? = if (sharedPreferences!!.contains(name)) sharedPreferences!!.getInt(name, 0) else null
fun getLong(): Long? = if (sharedPreferences!!.contains(name)) sharedPreferences!!.getLong(name, 0) else null
fun getString(): String? = if (sharedPreferences!!.contains(name)) sharedPreferences!!.getString(name, "") else null
fun setBoolean(value: Boolean?) = value?.let { sharedPreferences!!.edit { putBoolean(name, value) } } ?: remove()
fun setFloat(value: Float?) = value?.let { sharedPreferences!!.edit { putFloat(name, value) } } ?: remove()
fun setInt(value: Int?) = value?.let { sharedPreferences!!.edit { putInt(name, value) } } ?: remove()
fun setLong(value: Long?) = value?.let { sharedPreferences!!.edit { putLong(name, value) } } ?: remove()
fun setString(value: String?) = value?.let { sharedPreferences!!.edit { putString(name, value) } } ?: remove()
fun exists(): Boolean = sharedPreferences!!.contains(name)
fun remove() = sharedPreferences!!.edit { remove(name) }
}
}
Now from anywhere within your app you can get a value like this:
val heightInCentimeters: Int? = AppPreferences.heightInCentimeters
val heightOrDefault: Int = AppPreferences.heightInCentimeters ?: 170
Setting a value to the SharedPreferences is just as easy:
AppPreferences.heightInCentimeters = 160 // sets a new value
The above is extracted from my FitnessTracker project. See this file for a full example.
Solution 2:[2]
As coroutineDispatcher has commented you should pass in the shared preferences into the interceptor's constructor and hold a reference to them.
Try this:
class ServiceInterceptor(private val prefs: SharedPreferences): Interceptor {
val token: String get() = prefs.getString("token")
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
if(request.header("No-Authentication") == null){
if (request.url.toString().contains("/user/signin") === false) {
// Add Authorization header only if it's not the user signin request.
request = token
.takeUnless { it.isNullOrEmpty }
?.let {
request.newBuilder()
.addHeader("Authorization", "Bearer $it")
.build()
}
?: request
}
}
return chain.proceed(request)
}
}
The interceptor now takes in a reference to shared preferences so the dependency has been inverted and it can allow for easy testing by stubbing the passed SharedPreferences.
And it can be instanatiated like this:
ServiceInterceptor(PreferenceManager.getSharedPreferences())
Solution 3:[3]
You can create a singleton class for SharedPreference and then you can access it from any class you want.
Example
class SessionManager private constructor(context:Context) {
private val prefs:SharedPreferences
private val editor:SharedPreferences.Editor
var token:String
get() {
return prefs.getString("token", "")
}
set(token) {
editor.putString("token", token)
editor.apply()
}
init{
prefs = context.getSharedPreferences("Your_Preference_name", Context.MODE_PRIVATE)
editor = prefs.edit()
}
companion object {
private val jInstance:SessionManager
@Synchronized fun getInstance(context:Context):SessionManager {
if (jInstance != null)
{
return jInstance
}
else
{
jInstance = SessionManager(context)
return jInstance
}
}
}
}
Now you have to pass context in constructor of ServiceInterceptor and you can access SharedPreference like following.
val token = SessionManager.getInstance(context).token;
Solution 4:[4]
try this
val token = PreferenceManager.getSharedPreferences().getToken("","")
builder.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.addHeader("Authorization", "Bearer $token")
val request = requestBuilder.build()
chain.proceed(request)
}
return builder.build()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Kaaveh Mohamedi |
| Solution 3 | |
| Solution 4 | Madhav |
