如何在对象中获取上下文?

Posted

技术标签:

【中文标题】如何在对象中获取上下文?【英文标题】:How to get Context inside an Object? 【发布时间】:2019-11-09 04:07:22 【问题描述】:

我正在使用改造来获取一些数据,为此我在 Header 中传递了一个令牌以进行身份​​验证。 我想从我的改造客户端对象中的共享首选项中获取令牌,但我不知道如何?

我尝试使用函数在对象中获取上下文,但它给了我警告

Do not place android context classes in static fields (static reference to RetrofitClient which has field context pointing to Context); this is a memory leak (and also breaks Instant Run) less... 

我还尝试在我的改造界面中获取上下文,但我在没有警告的情况下获得了上下文,但我不知道从哪里获取共享首选项。

interface Api 
    var context:Context;
    @FormUrlEncoded
    @POST("getMerchantProductsSlideContent")
    fun getProductsForSlide(

 //Don't know how to get value from shared refercne to this header
        @Header("Authentication: Bearer ")

        @Field("token") token:String,
        @Field("deviceId") deviceId:String,
        @Field("content_receiver") content_receiver:String,
        @Field("content_type") content_type:String,
        @Field("data") data:Array<String>
    ):Call<DefaultResponse>

    fun getContext(mContext:Context)
        context = mContext
    


这是retrofitClient.kt

object RetrofitClient 

    private val AUTH = "Bearer $token"
    private const val BASE_URL = "http://192.168.1.5/Projects/Sitapuriya/public/"

    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor  chain ->
            val original = chain.request()

            val requestBuilder = original.newBuilder()
                .addHeader("Authorization", AUTH)
                .method(original.method(), original.body())

            val request = requestBuilder.build()
            chain.proceed(request)
        .build()

    val instance: Api by lazy
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()

        retrofit.create(Api::class.java)
    

这是我的改造界面

interface Api 
    @FormUrlEncoded
    @POST("getMerchantProductsSlideContent")
    fun getProductsForSlide(

        @Field("token2") token2:String,
        @Field("deviceId") deviceId:String,
        @Field("content_receiver") content_receiver:String,
        @Field("content_type") content_type:String,
        @Field("data") data:Array<String>

    ):Call<DefaultResponse>


[更新] 这是我的活动 n,我称之为改造

  val data = arrayOf(merchantId)
                RetrofitClient.instance.getContext(this)
                RetrofitClient.instance.getProductsForSlide(
                    token,
                    deviceId,
                    "MERCHANT",
                    "MERCHANT_VIEW_BASIC",
                    data
                ).enqueue(object:Callback<DefaultResponse>

                    override fun onFailure(call: Call<DefaultResponse>, t: Throwable) 
                       Toast.makeText(applicationContext,"ERROR: $t.message",Toast.LENGTH_LONG).show()
                    

                    override fun onResponse(
                        call: Call<DefaultResponse>,
                        response: retrofit2.Response<DefaultResponse>
                    ) 
                        Toast.makeText(applicationContext,"SUCCESS: $response.body()?.content",Toast.LENGTH_LONG).show()
                    

                )

我想从 Shared Preferences 中获取令牌并将其用作我的请求的标头,并且我知道要访问 Shared Preferences 我们需要一个上下文。如何在 Object 中获取上下文?

[UPDATE-2] 尝试过@Blundell 答案

interface Api 
   var token: String
    @FormUrlEncoded
    @POST("getMerchantProductsSlideContent")

    fun getProductsForSlide(
        @Header("Authentication: Bearer $token")
        @Field("token") token:String,
        @Field("deviceId") deviceId:String,
        @Field("content_receiver") content_receiver:String,
        @Field("content_type") content_type:String,
        @Field("data") data:Array<String>
    ):Call<DefaultResponse>

    fun setAuthHeader(token2:String)
        token = token2
    

但它给出了错误:注解参数必须是编译时常量

【问题讨论】:

调用getProductsForSlide方法的代码在哪里?你可以在那里访问 SharePreferences 你最好使用 dagger2 或添加拦截器或通过参数传递标头 检查对您有帮助的项目。 github.com/zigic88/Dagger2-Retrofit 如果你想从 Shared 中获取数据而不需要对代码进行重大更改,你可以简单地通过扩展应用程序类的静态方法来获取上下文,然后创建 sharedpreferences 对象。 @Blundell 请检查更新的问题 【参考方案1】:

尝试在您的活动中获取令牌(您可以使用活动的上下文并从共享首选项中获取令牌)并将此令牌传递给您的改造类。

还可以尝试阅读有关依赖注入、dagger2、koin 等的内容,为您的类提供不同的依赖项

interface Api 
    @FormUrlEncoded
    @POST("getMerchantProductsSlideContent")
    fun getProductsForSlide(
        @Header("Authentication") token:String,
        @Field("deviceId") deviceId:String,
        @Field("content_receiver") content_receiver:String,
        @Field("content_type") content_type:String,
        @Field("data") data:Array<String>
    ):Call<DefaultResponse>

在你的活动中:

val prefToken = // get it from prefences
val token = "Bearer " + prefToken

【讨论】:

是的,我可以在我的活动中获取令牌,但我不知道如何在改造课程中传递它。我尝试了传递令牌的方法,请查看我更新的问题(UPDATE-2) @PrathamVaidya 试试这个 谢谢你的解决方案有效,我是第一次使用改造。【参考方案2】:

与其尝试将上下文存储在单例中,不如存储您要发送的标头。访问 Activity 中的上下文和共享首选项。

变化:

 RetrofitClient.instance.getContext(this)

类似

 RetrofitClient.instance.setAuthHeader(getSharedPreferences().getString("Header"))

【讨论】:

先生,我试过你的答案,但它给了我一个错误。请检查我更新的问题(UPDATE-2)

以上是关于如何在对象中获取上下文?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Apollo Server 中正确键入上下文对象?

在托管对象上下文中添加 NSSortDescriptor 以获取请求?

无法在阿波罗服务器上下文中获取会话?

从 Spring 安全上下文中获取 userAuthentication 对象

如何在模板标签中获取当前用户?

如何在给定上下文的情况下获取布局充气器?