当前位置: 首页 > 知识库问答 >
问题:

如何避免等待主线程时添加头请求使用改造?

鄢雅畅
2023-03-14

我使用这个来配置我的改装:

 RestAdapter restAdapter = new RestAdapter.Builder()

            //add headers to requests
            .setRequestInterceptor(getAuthenticatedRequestInterceptor())
            .setEndpoint(BASE_URL)
            .setConverter(new GsonConverter(getGson()))
            .build();

GetAuthenticatedRequestInterceptor()方法将头添加到请求:

public AccountRequestInterceptor getAuthenticatedRequestInterceptor() {
    AccountRequestInterceptor interceptor = new AccountRequestInterceptor();
    Map<String, String> headers = new HashMap<>();
     String accessToken = null;
    try {
        accessToken = TokenProvider.getInstance(mContext).getToken();
    } catch (InterruptedException e) {

    }
    headers.put(HeadersContract.HEADER_AUTHONRIZATION, O_AUTH_AUTHENTICATION + accessToken);
    interceptor.setHeader(headers);
    return interceptor;
}

getToken()方法为:

private synchronized string getToken() throws InterruptedException {
    if (!isRefreshing()) {
        //This is very important to call notify() on the same object that we call wait();
        final TokenProvider myInstance = this;
        setRefreshing(true);

        MyApplication.getRestClient().getAccountService().getRefreshedToken(mLoginData.getRefreshToken())
                .subscribe(new Observer<LoginResponse>() {
                    @Override
                    public void onCompleted() {
                        synchronized (myInstance) {
                            setRefreshing(false);
                            myInstance.notifyAll();
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        synchronized (myInstance) {
                            setRefreshing(false);
                            myInstance.notifyAll();
                        }
                    }

                    @Override
                    public void onNext(LoginResponse loginResponse) {
                        synchronized (myInstance) {
                            mLoginData = loginResponse;
                            mAccountProvider.saveLoginData(loginResponse);
                            myInstance.notifyAll();
                        }
                    }
                });
    }
    this.wait();
    return mLoginData.getToken();
}

TokenProvider.GetInstance(mContext).GetToken()在主线程上有一个wait()来获取异步方法的响应,我知道这是一个不好的做法,但我需要这个方法来等待响应从其中获取令牌,然后返回令牌。我如何在一个单独的线程中这样做,以避免在主线程上等待?

注:

1-在任何带有改装的请求之前调用此命令。

2-我读了这篇文章,我知道我可以在请求失败后刷新令牌,但出于业务原因,我希望避免出现无效令牌。

3-我在我的activity调用MyApplication.GetRestClient().GetAccountService().Login(loginRequest,Callback...)并且在添加令牌之前,所有事情都发生在后台线程中。所以我想使用我的令牌,不要阻塞主线程。

更新:我在新的OKHTTP中添加了以下拦截器

public class RequestTokenInterceptor implements Interceptor {
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request request = chain.request();
        Request newRequest;
        try {
            Log.d("addHeader", "Before");
            String token = TokenProvider.getInstance(mContext).getToken();
            if (token != null) {
                newRequest = request.newBuilder()
                        .addHeader("Bearer", token)
                        .build();
            } else {
                // I want to cancel the request or raise an exception to catch it in onError method
                // of retrofit callback.
            }
        } catch (InterruptedException e) {
            Log.d("addHeader", "Error");
            e.printStackTrace();
            return chain.proceed(request);
        }
        Log.d("addHeader", "after");
        return chain.proceed(newRequest);
    }
}

现在,如果token为null,我如何取消请求或在reverfit回调的onError方法中引发一个异常来捕获它呢?

共有1个答案

於宾白
2023-03-14

这是一个有点奇怪的问题,但让我试着帮你。:)

正如您所知,您可以使用响应拦截器在一个失败请求后通过修改刷新令牌。

让我们尝试在请求之前使用拦截器。

public class RequestTokenInterceptor implements Interceptor {
   @Override
   public Response intercept(Chain chain) throws IOException {
      Request request = chain.request();
      // Here where we'll try to refresh token.
      // with an retrofit call
      // After we succeed we'll proceed our request
      Response response = chain.proceed(request);
      return response;
   }
}

在创建api时,创建一个新的HttpClient:

OkHttpClient client = new OkHttpClient();
client.interceptors().add(new RequestTokenInterceptor());

并将http客户端添加到适配器,如下所示:

.setClient(new OkClient(client))

如果这样做有效,在每个请求之前,您将尝试首先刷新令牌,然后继续您的api请求。所以在ui中,与正常的api调用没有区别。

编辑:

我也在编辑我的答案。如果要在令牌为空的情况下返回一个else大小写中的错误,则可以在else大小写中创建自定义响应:

private Response(Builder builder) {
    this.request = builder.request;
    this.protocol = builder.protocol;
    this.code = builder.code;
    this.message = builder.message;
    this.handshake = builder.handshake;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.networkResponse = builder.networkResponse;
    this.cacheResponse = builder.cacheResponse;
    this.priorResponse = builder.priorResponse;
  }

也可以简单地返回空响应。如果您构建自定义响应并将代码设置为不是200,例如401或400+,您将在改型的callbacks failure方法中收到该响应。你想做什么就做什么。

如果您返回null,我想您将得到一个RuntimeException,并且仍然可以在回调的failure方法中捕获响应。

在else中创建自己的响应后,您可以创建自定义回调,捕获空响应,并按需要转换自定义错误,如下所示:

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

    public abstract void failure(YourCustomException ex);

    public abstract void success(T responseBean);

    @Override
    public void success(T baseResponseBean, Response response) {
        if (response == null) {
            // Here we catch null response and transform it to our custom     Exception
            failure(new YourCustomException());
        }
        } else {
            success(baseResponseBean);
        }
    }

    @Override
    public void failure(RetrofitError error) {
        // Here's your failure method.
        // Also you can transform default retrofit errors to your customerrors
        YourCustomException ex = new YourCustomException();
        failure(ex);
    }
}

我想这能帮你。

编辑2:

您可以像下面这样构建一个新的响应。在Response类中有一个builder模式。你可以从那里查。

Response response = new Response.Builder().setCode(401).setMessage("Error Message").build();
 类似资料:
  • 问题内容: 我遇到的问题是,有时我启动的线程在调用它之前就完成了。看来这使我的程序等待不再发生的事情()。如何确保不等待线程完成? 问题答案: 如果您阅读JavaDocs for Thread,它将告诉您 永远不要在Thread对象上使用。您应该使用join()

  • 我刚开始使用Selenium Web驱动程序测试一个网上银行交易应用程序。 我喜欢,但有些事让我很恼火。假设我使用以下代码访问登录屏幕: 我也试过: 但这没有帮助,因为这行似乎只有在页面完全加载时才执行。 编辑:我和这里的一个人谈过了..他告诉我ipinvite.iperceptions.com不是我们的应用程序调用的。!!!事实上,当我在FF中加载站点时,我没有看到这个调用?! Selenium

  • 问题内容: 我正在尝试编写一个JS代码,如果给定的数字已经存在于数据库中,它将取消“ btn_submit”按钮.onclick事件。我使用AJAX向数据库查询给定的编号,并确定是否应将数据发送到将上传问题的.php站点。为了确定这一点,我需要numOfRows变量的值,但是因为我在AJAX中将其设置为0,所以validation()函数将在我的AJAX查询完成之前完成,这将导致始终表示给定数字不

  • 问题内容: 更新记录时,我反复出现锁定超时超出异常的情况。 我正在使用Java Struts 2.1 Hibernate配置。使用的数据库是MYSQL。 任何人都知道如何解决它。 问题答案: 这里有一些建议: “ 锁定等待超时 ”通常发生在事务正在等待要更新的数据行上,而该行已被某些其他事务锁定时。 在大多数情况下,问题出在数据库方面。可能的原因可能是表格设计不当,数据量大,约束等。 请查看这个详

  • 问题内容: 我找不到如何测量线程等待锁定的时间。我必须确定一个线程是否正在等待锁定超过1秒,如果需要,则运行另一个线程。谢谢! 问题答案: 试试这个:

  • 我打算在主线程中启动2个线程,主线程应该等到所有2个子线程完成,我就是这样做的。 在上面的代码中,确实让主线程等待子线程,但问题是,在第一个线程完成之前不会创建第二个线程。这不是我想要的。 我想要的是,这两个线程立即在主线程中创建,然后主线程等待它们完成。似乎做不到,是吗? 我想,也许我可以通过一个信号灯来完成这项工作,但还有别的方法吗?