为什么NetworkManager.addToQueueAndWait的多个并行调用相互干扰?

时间:2019-02-11 15:00:05

标签: android codenameone

来自不同线程(Timer-1和EDT)的jsonRequest()方法的多次调用确实会相互干扰,甚至一个调用都将返回上一次调用的结果

我的CodeNameOne应用程序使用后台线程(Timer-1)每秒检索和显示REST服务中的数据,它允许用户发出命令,这些命令也从EDT线程发出REST调用。

private Map<String, Object> jsonRequest(String url, String body, String cmd, int timeoutMs) {
    long startTs = System.currentTimeMillis();

    try {
        request = new ConnectionRequest();
        request.setReadResponseForErrors(true);
        // request.setTimeout(timeoutMs);
        // Shai: Timeout in Codename One is currently limited to connection timeout and 
        // doesn't apply to read timeout so once a connection is made it will last
        request.setHttpMethod(cmd); 
        request.setPost(cmd.equalsIgnoreCase("POST") || cmd.equalsIgnoreCase("PUT") || cmd.equalsIgnoreCase("PATCH"));
        if (body != null) {
            request.addRequestHeader("Accept", "application/json");
            request.setContentType("application/json");
            request.setRequestBody(body);
            request.setWriteRequest(true);
        }
        request.setUrl(url);
        NetworkManager.getInstance().addToQueueAndWait(request);
        long duration = System.currentTimeMillis() - startTs;
        Log.p(cmd + ": " + url + " " + duration + " ms");

        if (request.getResponseCode() >= 400 || request.getResponseData() == null) {
            Log.p("responseCode=" + request.getResponseCode() + " responseData=" + request.getResponseData());
            return null;
        }
        Log.p(cmd + ": " + url + " " + new String(request.getResponseData()));
        Map<String, Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(request.getResponseData()), "UTF-8"));
        return result;
    } catch (Exception e) {
        problemHandler.handle(cmd, url, e);
    }
    return null;
}

实际上,多次调用的结果混杂在一起。 我希望每次对addToQueueAndWait()的调用都等待正确的结果,并在结果在那里时返回。 我观察到这个问题在Android上比在iOS或模拟器上更常见。

1 个答案:

答案 0 :(得分:1)

我怀疑那是你所看到的。我看到请求是在类级别定义为变量的,所以我猜您正在看到一种典型的竞争情况,其中请求变量在发送时被替换,而到解析时则是另一个对象。

由于网络已经在单独的线程上运行(因此通常在 0 | 1 | 2 ---+---+--- 3 | 4 | 5 ---+---+--- 6 | 7 | 8 方法中确定),因此无需使用线程进行轮询。

我建议对响应完成后调用的单个调用使用计时器。

一个更好的方法是使用websockets:https://www.codenameone.com/blog/introducing-codename-one-websocket-support.html

使用websocket,服务器可以推送更新通知。这将节省您不断轮询服务器的需求。这样可以节省设备的电池寿命和服务器/设备上的资源。