0

I use RxJava and Retrofit to execute OkHttp requests. I can see in Android Studio's network profiler that my requests are leaked, because they are keeping the AsyncTask threads alive. No response for them and their size is null. I can see the original request, the token request, the updated request in the Thread View in network profiler. But the original request never finishes.

In extreme cases, like in QA environment where the tokens are refreshed every minute for some reason the threadpool becomes full and no more calls can be made. I think we can call chain.proceed as many times as we want, but I think the error is still somewhere there. Here is the interceptor code:

private static okhttp3.Interceptor oauthInterceptor = chain -> {
    OAuthToken token = OAuthToken.getOAuthToken();
    long initialTokenCreated = token.getCreatedUtc();

    Request request = changeTokenInRequest(chain.request(), token);
    Response response = chain.proceed(request);
    boolean forceTokenRefresh = false;

    if (initialTokenCreated != token.getCreatedUtc()) {
        // Then the token has been updated since we started this request
        request = changeTokenInRequest(chain.request(), token);
        response = chain.proceed(request);
    }

    String jsonType = "application/json";
    if (!response.body().contentType().toString().contains(jsonType)) {
        forceTokenRefresh = true;
    }

    // 401: Forbidden, 403: Permission denied
    if (forceTokenRefresh || ((response.code() == 401 || response.code() == 403)
            && OAuthToken.getOAuthToken().getRefreshToken() != null)) {
        OAuthToken refreshedToken = refreshToken();
        if (refreshedToken == null) {
            // Then there was a problem refreshing the token
            return response;
        }
        // Recreate the request with the new access token
        request = changeTokenInRequest(chain.request(), refreshedToken);
        return chain.proceed(request);
    } else {
        return response;
    }
};

protected static okhttp3.Request changeTokenInRequest(Request request, OAuthTokenBase token) {
    Headers.Builder builder = request.headers().newBuilder().removeAll("Authorization");
    if (!TextUtils.isEmpty(token.getTokenType()) && !TextUtils.isEmpty(token.getAccessToken())) {
        builder = builder.add("Authorization", token.getTokenType() + " " + token.getAccessToken());
    }
    request = request.newBuilder().headers(builder.build()).build();
    return request;
}

That's how I make the calls:

public static Observable<ResultPaginatedReply<BasicUser>> getGroupsMembers(String type, String id, int page) {
    return getMsApiService().getGroupsMembers(type, id, page)
            .subscribeOn(Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR))
            .observeOn(AndroidSchedulers.mainThread());
}
Herrbert74
  • 2,578
  • 31
  • 51

1 Answers1

2

Turns out that if you don't use the Authenticator class in OkHttp like me here, than you have to manually close the response body when the token is refreshed. @DallinDyer's comment helped me here.

So I added

            response.body().close();

after the error checks and voilĂ .

Herrbert74
  • 2,578
  • 31
  • 51