19

I would like to save some stuff on the SharedPreferences while being on a Interceptor. I can't find a way to do it because i can't find a way to access the context on the Interceptor (so not possible to use PreferencesManager, etc).

public class CookieInterceptor implements Interceptor {

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

    PreferenceManager.getDefaultSharedPreferences(Context ??)

}}

Any ideas ?

I'm using AndroidStudio & last version of OkHttp.

Thanks ;)

se0
  • 201
  • 1
  • 2
  • 4

4 Answers4

11

You can create a class that allows you to retrieve the context from anywhere (i.e. your interceptor):

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

Then add this to your manifest like this:

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

And then in your interceptor, do this:

PreferenceManager.getDefaultSharedPreferences(MyApp.getContext());
user1282637
  • 1,827
  • 5
  • 27
  • 56
  • 7
    Would it not cause of memory leak? Storing application object in a static variable. – Rohit Bandil Jun 11 '17 at 20:44
  • Passing context to interceptor via constructor is a better solution and does not cause memory leak. – Mahdi Moqadasi Apr 06 '19 at 11:52
  • Making MyApp static is not a good idea. What if one is calling the API from the module project? Module project doesn't have an application class. – Mohit Rajput Apr 08 '19 at 12:49
  • This solution should be avoided as it can cause memory leak. – rzaaeeff Jan 28 '20 at 09:28
  • 1
    `Application` is already a singleton - storing it in a `static` field does not cause a memory leak. This isn't true for other `Context` sources (Activities, Services), where storing a `static` reference can cause memory leaks, but using `Application` in this way is fine. – PPartisan Jan 28 '20 at 09:43
6

You should not keep static instance of context, since it will lead to memory leak. Instead, you can change your architecture a bit to be able to send context as a parameter to the Interceptor.

// 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();
    }
}

Then you can use that context instance in your Interceptor class.

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

    }
}

Good luck!

rzaaeeff
  • 850
  • 1
  • 10
  • 18
0

Use dependency injection and supply a SharedPreferences (not Context - in your example your Interceptor requires SharedPreferences) instance via the constructor:

class CookieInterceptor implements Interceptor {

    private final SharedPreferences prefs;

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

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

}
PPartisan
  • 8,173
  • 4
  • 29
  • 48
0

I've been battling with this myself for days, and the solution was simple in the end using Hilt to inject it into the parent class.

  1. Inject the parent class with Hilt
  2. Add the application context to the parent class constructor
  3. Send the context as a parameter to the interceptor
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)

}}
maganthro
  • 361
  • 1
  • 3
  • 10