首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >RxJava 2/ Retrofit 2- NetworkOnMainThreadException

RxJava 2/ Retrofit 2- NetworkOnMainThreadException
EN

Stack Overflow用户
提问于 2017-05-16 17:05:29
回答 3查看 5.4K关注 0票数 8

我需要执行一个请求,如果我的令牌过期了,我需要刷新它并重试请求。

我就是这样做的,目前我可以刷新令牌,但它会抛出一个NetworkOnMainThreadException。它完成请求,更新令牌并到达日志,但该异常会杀死我。我怎么才能避免呢?

代码语言:javascript
运行
复制
    public Observable<Estabelecimento> listarEstabelecimentos() {
    return Observable.defer(this::getListarEstabelecimentoObservable)
            .retryWhen(throwableObservable -> throwableObservable.flatMap(
                    throwable -> {
                        if (throwable instanceof UnauthorizedException) {
                            return mRequestManager.getTokenObservable(AutoAtendimentoApplication.getContext())
                                    .doOnNext(response -> /* log stuff */)
                                    .flatMap((Function<AuthResponse, ObservableSource<?>>) response2 ->
                                            getListarEstabelecimentoObservable()
                                                    .doOnNext(estabelecimento ->
                                                            /* log stuff */)
                                                    )
                                    );
                        }
                        return Observable.error(throwable);
                    }));
}

NetWorkErrorHandler:

代码语言:javascript
运行
复制
    public <T> T  processError(Response<T> response ) {
    switch (response.code()) {
        case 401:
            throw new UnauthorizedException();
        default:
            return response.body();
    }
}

令牌:

代码语言:javascript
运行
复制
       private Observable<AuthResponse> getToken(Context context,
                                          @GrantType.GrantTypeDef String grantType, @Nullable String refreshToken) {

    SessionManager sessionManager = SessionManager.getInstance(context);
    Usuario usuario = sessionManager.getUser();

    AuthRequest request = new AuthRequest(usuario.getUsername(),
            usuario.getPassword(), grantType, refreshToken);

    return mAuthAPIService.getToken(request)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .map(response -> storeTokens(response, context));
}

编辑1:我很确定这个问题发生在平面图中,放置subscribeOn并不能解决问题

编辑2:代码更新

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-05-16 17:08:25

您的网络运行在主线程上,您可以通过将observeOn(AndroidSchedulers.mainThread())subscribeOn(Schedulers.io())添加到可观察的线程中来解决这个问题。

observeOn(...)意味着在指定的线程上发送结果--在本例中是UI线程。

subscribeOn(...)调用基本上就是处理请求的地方。如果省略,计算将在当前线程上完成。

票数 10
EN

Stack Overflow用户

发布于 2017-05-16 19:50:17

好的,让我试着用简单的英语解释一下。当您使用AndroidSchedulers.mainThread()时,它将当前块封装在主线程中,它与活动中的任何方法没有什么不同。主上下文不允许执行网络请求,因此您的请求失败了。要纠正这种情况,您的可观察到的需求需要更改以适应执行。

要测试这一理论,请将所有的AndroidSchedulers.mainThread()更改为Schedulers.io(),因此您将注释掉对ui处理的所有调用,比如To消息,并留下简单的日志消息,尝试并查看发生了什么。

您需要重构本节,因为它调用主线程。

代码语言:javascript
运行
复制
 if (throwable instanceof UnauthorizedException) {
                            return mRequestManager.getTokenObservable(AutoAtendimentoApplication.getContext()).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io())
                                    .doOnNext(response -> Log.i("NEXT", "OK")).doOnError(throwable1 -> Log.i("ONERROR", "NOT OK"));

这里有一个理论解决方案,不要将getToken包装在可观察的范围内,创建一个可以独立调用getToken的类,让它返回一个可以观察到的,然后您可以订阅和观察的类。实际上,目前您将上面的内容封装在主线程中,我不知道如何使此简化}

票数 1
EN

Stack Overflow用户

发布于 2017-05-26 17:21:04

问题肯定在你的getToken上。您不需要observeOn和subscribeOn:

代码语言:javascript
运行
复制
    return mAuthAPIService.getToken(request)
        .map(response -> storeTokens(response, context));

添加这些行会产生错误。我确实认为你需要在最终订户中指定它的唯一位置。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44007570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档