0

我正在使用 PreferenceScreen 来设置我想在我的改造 API 服务中使用的身份验证密钥和 url。因此,要获取身份验证密钥,我需要访问我的 API 服务中的 SharedPreferences。但要做到这一点,我需要一个上下文。如何将上下文传递给我的改造实例?

这是我的 API 服务:

private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(???)

private val BASE_URL = sharedPreferences.getString("api_url","")
private val TTN_KEY = sharedPreferences.getString("access_key","")

private val loggingInterceptor: HttpLoggingInterceptor =
    HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)

private val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val originalRequest = chain.request()
        val newRequest = originalRequest.newBuilder()
            .addHeader("Authorization", "key $TTN_KEY")
            .build()
        chain.proceed(newRequest)
    }
    .addInterceptor(loggingInterceptor)
    .build()

private val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(MoshiConverterFactory.create())
    .client(okHttpClient)
    .build()

interface TTNApiService {
    @GET("devices")
    suspend fun getDevices(): List<String>

    @GET("query/{device-id}")
    suspend fun getDeviceValues(@Path("device-id") id: String): List<NetworkValue>

    @GET("query")
    suspend fun getValues(): List<NetworkValue>
}

// public object used to access the retrofit instance
object TTNApi {
    val retrofitService: TTNApiService by lazy {
        retrofit.create(TTNApiService::class.java)
    }
}
4

2 回答 2

0

一个基本的解决方案是将应用程序上下文存储在扩展应用程序类的类中。像这样

class MyApp : Application() {
    
    override fun onCreate() {
        instance = this
        super.onCreate()
    }

    companion object {
        var instance: MyApp? = null
            private set

        val context: Context?
            get() = instance
    }
}

然后你可以像这样在你的文件中获取上下文

private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MyApp.context)

还有一个首选和正确的方法是使用像Koin这样轻量级且易于使用的依赖注入框架

于 2020-11-24T13:40:12.893 回答
0

我想我找到了解决办法。我不知道它是否干净,但它现在可以工作。如果您有任何建议,请告诉我!

  • 我重构了我的界面,如下所示
  • 将我的 ViewModel 更改为从 AndroidViewModel 而不是 ViewModel 扩展,以便我可以使用应用程序上下文
  • 每次我想调用我使用的 APITTNApiService.create(application).getDeviceValues(deviceId)
interface TTNApiService {
    @GET("devices")
    suspend fun getDevices(): List<String>

    @GET("query/{device-id}")
    suspend fun getDeviceValues(@Path("device-id") id: String): List<NetworkValue>

    @GET("query")
    suspend fun getValues(): List<NetworkValue>

    companion object{
        private lateinit var BASE_URL : String;
        private lateinit var TTN_KEY : String;

        fun create(context: Context): TTNApiService{
            val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)

            BASE_URL = sharedPreferences.getString("api_url","").toString()
            TTN_KEY = sharedPreferences.getString("access_key","").toString()

            val loggingInterceptor: HttpLoggingInterceptor =
                HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)

            val okHttpClient = OkHttpClient.Builder()
                .addInterceptor { chain ->
                    val originalRequest = chain.request()
                    val newRequest = originalRequest.newBuilder()
                        .addHeader("Authorization", "key $TTN_KEY")
                        .build()
                    chain.proceed(newRequest)
                }
                .addInterceptor(loggingInterceptor)
                .build()

            return Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create())
                .client(okHttpClient)
                .build()
                .create(TTNApiService::class.java)
        }
    }
}
于 2020-11-24T13:47:45.073 回答