Retrofit“IllegalStateException:Already executed”

34

我有一个Retrofit网络调用,希望每5秒运行一次。我的当前代码:

Handler h = new Handler();
int delay = 5000; //milliseconds

h.postDelayed(new Runnable() {
    public void run() {
        call.enqueue(new Callback<ApiResponse>() {
            @Override
            public void onResponse(Response<ApiResponse> response) {
                Log.d("api", "response: " + response.body().getPosition().getLatitude().toString());
            }

            @Override
            public void onFailure(Throwable t) {

            }
        });
        h.postDelayed(this, delay);
    }
}, delay);

这段代码只会运行一次,但是随后抛出以下异常:

java.lang.IllegalStateException: Already executed. at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:52) at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.enqueue(ExecutorCallAdapterFactory.java:57) at orbyt.project.MyFragment$1.run(MyFragment.java:93)

问题出在哪里?

额外提供:有没有更好的处理方法?我会在每次更新时更新一个地图。我考虑尝试使用Rx,但不确定这是否是适当的用例,或如何实现它。


你的网络调用是否可能超过5秒钟,所以当第二次迭代开始时,第一次迭代还没有结束?延迟并不是在第一次迭代结束后开始的,而是在你调用第一次迭代的5秒钟后开始的。 - TooManyEduardos
@TooManyEduardos 嗯,我知道第一个调用完成了,因为我正在记录响应,并且实际上正在获取数据。 - Orbit
但是日志只会显示接收到的数据,而不是网络连接完成。它可能仍在5秒窗口内关闭元素。这只是一个想法,但尝试将延迟增加到15秒,看看问题是否消失。 - TooManyEduardos
@TooManyEduardos将延迟更改为15秒,仍然收到相同的错误。 - Orbit
调用偶数函数会显示“无法执行两次”。 - njzk2
显示剩余2条评论
1个回答

83
Call 只能使用一次。 它的文档 告诉您如何多次使用一个调用:

使用 clone() 以相同的参数对同一Web服务器进行多次调用; 这可以用于实现轮询或重试失败的调用。

因此,分别使用 call.clone().enqueue(..)(异步)和 call.clone().execute()(同步),确保您每个请求都有一个新的、未执行的 Call

1
嗨@Jake Wharton,我正在使用以下代码多次调用同一个API:if(call.isExecuted()){call.cancel();} call.clone()。enqueue(..),我只想从最后/最新的调用中接收响应,但是每个调用都会收到响应? - Deven
@Deven,如果你限制Ok每次只能处理一个请求,那么这可能是可靠的。可以使用以下代码实现:new Retrofit.Builder().callFactory(new OkHttpClient.Builder().dispatcher(new Dispatcher().setMaxRequests(1).setMaxRequestsPerHost(1)).build()).build();我曾经看到过多个排队的请求以不同的顺序完成。 - swooby
我有一个疑问。我可以使用call.cancel()代替吗? - Jorge Alejandro Puñales

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接