Android / Kotlin:在翻新拦截器内部访问sharedPreferences

时间:2019-09-19 09:12:21

标签: android kotlin retrofit retrofit2

这里是一个改装拦截器,用于在请求内自动注入令牌。我正在尝试从sharedPreferences获取此令牌,但是getSharedPreferences在那里不可用。

如何从此拦截器内的共享首选项中检索我的令牌?

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)
    }

}

4 个答案:

答案 0 :(得分:2)

Kotlin 中有一个简单的解决方案–只需将代码复制并粘贴到新的networkx文件中,然后遵循4个TODO步骤在代码中概述:

AppPreferences.kt

现在,您可以在应用中的任何地方获取价值,如下所示:

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 remove() = sharedPreferences!!.edit { remove(name) }
    }
}

val heightInCentimeters: Int? = AppPreferences.heightInCentimeters val heightOrDefault: Int = AppPreferences.heightInCentimeters ?: 170 设置值很简单:

SharedPreferences

答案 1 :(得分:0)

您可以为singleton class创建一个SharedPreference,然后可以从任何所需的class中访问它。

示例

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
      }
    }
  }
}

现在,您必须在context的{​​{1}}中传递constructor,然后才能像下面那样访问ServiceInterceptor

SharedPreference

答案 2 :(得分:0)

正如coroutineDispatcher评论的那样,您应该将共享首选项传递到拦截器的构造函数中,并保留对它们的引用。

尝试一下:

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)
    }

}

拦截器现在采用了对共享首选项的引用,因此依赖项已被反转,并且可以通过对传递的SharedPreferences进行存根来简化测试。

可以这样实例化:

ServiceInterceptor(PreferenceManager.getSharedPreferences())

答案 3 :(得分:0)

尝试

val令牌= 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()