In my app I use Retrofit2 with a service to collect data on eBay. For this I need a token that is valid for 2 hours.
If I start the query, the token is taken over from my database and works. If the 2 hours have expired, the token will be re-entered in the database. But when the data is picked up again on Ebay, I get an error 401 - unauthorized access. I use a MainActivity
and invite the fragments there. As soon as I restart the app, everything works again. I suspect that the service does not update the token when query and use the old token. How can I end the service or query and start with the new token? What could be the problem?
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null) {
String auth = "Bearer " + token;
String cont = "application/json";
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.addInterceptor(chain -> {
Request request = chain.request().newBuilder()
.addHeader("Authorization", auth)
.addHeader("Content-Type", cont)
.build();
return chain.proceed(request);
});
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient.build())
.build();
}
return retrofit;
}
When picking up the token from the database, according to log, the current token is always read out. But the feedback from eBay is always the 401 error.
Edit: The OkHttp connection keeps the token. Since the same address is called up, the previous connection with the old token is used. How can I replace/replace the token?
Your method has the below logic:
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null) {
// ...
}
return retrofit;
}
Because retrofit
is defined as static it will keep its given value from the moment it's first assigned / even without the static
keyword it would keep that value for the duration of the instantiated object's lifetime.
The first time getClient
is called the value is null, so the logic in the if
block is run & the retrofit gets defined with an Authorization header which includes the given token
value.
However, subsequent calls to getClient
will see that retrofit
is already assigned, so will just return it; regardless of what parameters were sent to the method (i.e. even if there's a new token), and as the variable is static this will be true even if you've created a new instance of your RetrofitClient
.
There are various solutions:
Remove the if
statement so that the logic within it is run every time. This will incur some performance overhead (i.e. as you're having to do work for every request, even if the baseUrl
and token
values are the same as previously), but will return a Retrofit
instance with the correct values every time. If doing this, you may not need the private static Retrofit retrofit = null;
line at all; as the value is created and returned entirely within your getClient
method; so making the value accessible outside of this context just adds risk.
Remove the static
keyword and create a new instance of the RetrofitClient
class for each new baseUrl + token value (i.e. each time your token expires). This may require additional refactoring, as you'll then require an instance of your class to access the getClient
method.
Add code such as below, to check if the values are different to previous requests and update retrofit
only when required. E.g.
private static Retrofit retrofit = null;
private static String baseUrlCached = null;
private static String tokenCached = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null || (baseUrl != baseUrlCached || token != tokenCached)) {
// ...
}
return retrofit;
}