改造:如果响应代码为401,则重定向到登录活动

2022-09-01 11:55:27

如何从拦截器(非活动类)开始?我已经尝试了下面的代码(),但不适合我。LoginActivityInterceptor

拦截 器

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

这是我使用的当前解决方案,还有比这更好的解决方案吗?此解决方案必须在每次 API 调用时保持重复。

主要活动

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

            }
        });

答案 1

就个人而言,我建议在这里使用事件总线模式。你可以使用greenrobot实现或任何你想要的东西,因为它更多的是关于架构方法而不是具体的实现。

  1. 创建事件模型

    public class UnauthorizedEvent {
    
        private static final UnauthorizedEvent INSTANCE = new UnauthorizedEvent();
    
        public static UnauthorizedEvent instance() {
            return INSTANCE;
        }
    
        private UnauthorizedEvent() {
        }
    }
    
  2. 实现自定义,该自定义会破坏有关未经授权请求的事件Interceptor

    class UnauthorizedInterceptor implements Interceptor {
    
        @Override
        public Response intercept(@NonNull Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            if (response.code() == 401) {
                EventBus.getDefault().post(UnauthorizedEvent.instance());
            }
            return response;
        }
    }
    
  3. 创建处理BaseActivityUnauthorizedEvent

    public class BaseActivity extends Activity {
    
        @Override
        public void onStart() {
            super.onStart();
            EventBus.getDefault().register(this);
        }
    
        @Override
        public void onStop() {
            super.onStop();
            EventBus.getDefault().unregister(this);
        }
    
        @Subscribe
        public final void onUnauthorizedEvent(UnauthorizedEvent e) {
            handleUnauthorizedEvent();
        }
    
        protected void handleUnauthorizedEvent() {
            Intent intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
        }
    }
    
  4. 阻止启动LoginActivityLoginActivity

    public class LoginActivty extends BaseActivity {
    
        @Override
        protected void handleUnauthorizedEvent() {
            //Don't handle unauthorized event
        }
    }
    

    另一种方法是不在这里扩展。BaseActivity

  5. 注册您的拦截器

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new UnauthorizedInterceptor())
            .build();
    

优点:

  • 组件之间的松散耦合
  • Easaly 通过覆盖来扩展逻辑handleUnauthorizedEvent
  • 无需重写代码即可使用新类型的回调
  • 减少犯错误的人为因素(使用而不是CallbackBaseCallback)

缺点:

  • 事件总线模式使调试更加复杂
  • 多一个依赖关系或自己的实现,为项目带来新代码

另外,请注意,此示例不涵盖多线程问题。它解决了您处理未经授权的请求的问题。因此,如果两个请求收到 401,则可能会启动 2 个实例。LoginActivity


答案 2

考虑引入接口的自定义实现,例如:retrofit2.CallbackBaseCallback

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

}

现在,从调用方站点,您应该更改为:new Callback<Token>new BaseCallback<Token>

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

虽然,这种方法不能满足您的以下陈述:

所以我不必为每个api调用重复相同的代码

然而,我无法想出更好的方法。


推荐