如何在拦截器中访问上下文?

20

我想在拦截器中保存一些数据到SharedPreferences,但是我找不到访问Interceptor上下文的方法(所以无法使用PreferencesManager等)。

public class CookieInterceptor implements Interceptor {

@Override public Response intercept(Chain chain) throws IOException {

    PreferenceManager.getDefaultSharedPreferences(Context ??)

}}

有什么想法吗?

我正在使用AndroidStudio和最新版本的OkHttp。

谢谢;)

4个回答

11
你可以创建一个类,使你能够从任何地方(例如你的拦截器)检索上下文:
public class MyApp extends Application {
    private static MyApp instance;

    public static MyApp getInstance() {
        return instance;
    }

    public static Context getContext(){
        return instance;
    }

    @Override
    public void onCreate() {
        instance = this;
        super.onCreate();
    }
}

那么就像这样将它添加到清单文件中:

<application
    android:name="com.example.app.MyApp"

然后在你的拦截器中,做这个:

PreferenceManager.getDefaultSharedPreferences(MyApp.getContext());

8
将应用程序对象存储在静态变量中是否会导致内存泄漏? - Rohit Bandil
通过构造函数将上下文传递给拦截器是更好的解决方案,不会导致内存泄漏。 - Mahdi Moqadasi
将MyApp设为static并不是一个好主意。如果从模块项目中调用API会怎样呢?模块项目没有应用程序类。 - Mohit Rajput
应避免使用此解决方案,因为它可能会导致内存泄漏。 - rzaaeeff
1
“Application”已经是单例模式 - 将其存储在“static”字段中不会导致内存泄漏。但对于其他“Context”来源(如Activities、Services),存储静态引用可能会导致内存泄漏,但以这种方式使用“Application”是可以的。 - PPartisan

6

您不应该保留静态上下文实例,因为这会导致内存泄漏。相反,您可以稍微改变架构以便将上下文作为参数发送到拦截器中。

// in your network operations class
// where you create OkHttp instance
// and add interceptor
public class NetworkOperations {
    private Context context;

    public NetworkOperations(Context context) {
        this.context = context;

    OkHttpClient client = new OkHttpClient.Builder()
                // ... some code here
                .addInterceptor(new CookieInterceptor(context))
                // ... some code here
                .build();
    }
}

然后您可以在拦截器类中使用该上下文实例。

public class CookieInterceptor implements Interceptor {
    private Context context;

    public CookieInterceptor(Context context) {
        this.context = context;
    }

    @Override 
    public Response intercept(Chain chain) throws IOException {

        PreferenceManager.getDefaultSharedPreferences(context);

    }
}

祝你好运!


0

我自己已经和这个问题斗争了几天,最终使用Hilt将其注入到父类中的解决方法非常简单。

  1. 使用Hilt注入父类
  2. 将应用程序上下文添加到父类构造函数中
  3. 将上下文作为参数发送给拦截器
class RetrofitWithCookie @Inject constructor(
    @ApplicationContext context: Context
) {
    private val mContext = context

    fun createRetrofit(): Retrofit {
        val client: OkHttpClient
        val builder = OkHttpClient.Builder()
        builder.addInterceptor(CookieInterceptor(mContext))
        client = builder.build()

        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

public class CookieInterceptor implements Interceptor {

    private Context context;

    public CookieInterceptor(Context context) {
        this.context = (Context) context;
    }

    @Override public Response intercept(Chain chain) throws IOException {

        PreferenceManager.getDefaultSharedPreferences(Context)

}}

0

使用依赖注入,通过构造函数提供 SharedPreferences(而不是 Context - 在您的示例中,您的 Interceptor 需要 SharedPreferences)实例:

class CookieInterceptor implements Interceptor {

    private final SharedPreferences prefs;

    CookieInterceptor(SharedPreferences prefs) {
        this.prefs = prefs;
    }

    @Override public Response intercept(Chain chain) throws IOException {
        prefs.getXXX(...)
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接