Retrofit: Redirect to LoginActivity if response code is 401

Rick picture Rick · Jan 19, 2018 · Viewed 8.1k times · Source

How to start LoginActivity from the interceptor(non-activity class)? I have tried the code (Interceptor) below but not working for me.

Interceptor

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {

                Request newRequest = chain.request().newBuilder()
                        .addHeader("Authorization", "Bearer " + auth_token_string)
                        .build();

                Response response =  chain.proceed(newRequest);
                Log.d("MyApp", "Code : "+response.code());
                if (response.code() == 401){
                    Intent intent = new Intent(SplashActivity.getContextOfApplication(), LoginActivity.class);
                    startActivity(intent);
                    finish();  //Not working
                    return response;
                }

                return chain.proceed(newRequest);
            }
        }).build();

This is the current solution I'm using, is there any better solution than this? This solution has to keep repeat on every api call.

MainActivity

call.enqueue(new Callback<Token>() {
            @Override
            public void onResponse(Call<Token> call, Response<Token> response) {
                if(response.isSuccessful())
                {
                    //success
                }
                else
                {
                    Intent intent = new Intent(MainActivity.this.getApplicationContext(), LoginActivity.class);
                    startActivity(intent);
                    finish();
                }
            }
            @Override
            public void onFailure(Call<Token> call, Throwable t) {

            }
        });

Answer

azizbekian picture azizbekian · Apr 12, 2018

Consider introducing a custom implementation of retrofit2.Callback interface, e.g. BaseCallback:

public abstract class BaseCallback<T> implements Callback<T> {

    private final Context context;

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

    @Override
    public void onResponse(Call<T> call, Response<T> response) {
        if (response.code() == 401) {
            // launch login activity using `this.context`
        } else {
            onSuccess(response.body());
        }
    }

    @Override
    public void onFailure(Call<T> call, Throwable t) {

    }

    abstract void onSuccess(T response);

}

Now, from the caller site you should change new Callback<Token> with new BaseCallback<Token>:

call.enqueue(new BaseCallback<Token>(context) {
    @Override
    void onSuccess(Token response) {
        // do something with token
    }
});

Although, this approach doesn't fulfil your following statement:

so I don't have to keep repeat the same code over again for each api call

nevertheless, I cannot come up with a better approach.