Цикл, блокирующий асинхронный запрос от формирования.Почему и как решить? - PullRequest
0 голосов
/ 01 мая 2019

Я определяю, как обрабатывать ответ, который я получаю от своего сервера, в анонимном внутреннем классе, где я храню ответ в Map для обеспечения доступа извне этого внутреннего класса. Поскольку мой серверный вызов асинхронный, я реализовал цикл while, чтобы дождаться, когда результат будет помещен в карту, прежде чем вернуть его вызывающей функции. Однако, каким-то образом мой цикл не выполняется (насколько я могу судить, по крайней мере), и цикл, кажется, блокирует мой запрос от завершения, что, очевидно, приводит к бесконечному циклу.

public Login getLoginByUsername(String username)
    {
        long callID = counter.incrementAndGet();
        System.out.println("Start call");
        ServerConnection.get("myURI",null, new JsonHttpResponseHandler(){
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response){
                try {

                    System.out.println("Call success, enter result:");
                    callResults.put(callID, new CallResult(Login.parseFromJson(response)));
                    System.out.println(callResults.get(callID));

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println("start waiting");
       while(callResults.get(callID) == null){
            //wait
           System.out.print(".");
        }
        System.out.println("\nwaiting over, return result:");
        System.out.println(callResults.get(callID));
        return (Login) callResults.remove(callID).content;
}

Я уверен, что запрос работает просто отлично. Если я удаляю цикл (и возвращаю ноль, чтобы предотвратить доступ NPE к еще не завершенному результату), я могу видеть из выходов консоли, что запрос выполнен и дает действительный результат после завершения функции.

Я также попытался переместить весь запрос (ServerConnection.get) в другой метод на тот случай, если метод, выполняющий асинхронный вызов, должен по какой-то причине завершиться для выполнения вызова. Это тоже не помогло.

Кроме того, я никогда не получаю вывод консоли, определенный в цикле, поэтому я сомневаюсь, что он даже выполняется должным образом ...

Что здесь происходит, и как я могу это исправить?

Ответы [ 2 ]

0 голосов
/ 01 мая 2019

После обновления кода из-за связанной проблемы / вопроса ( Как вернуть ответ на вызывающую функцию? (Android-приложение вызывает Java REST-Server через JSON) , если вам интересно), я помещаю вокруг моей просьбы:

public Login getLoginByUsername(String username)
    {
        long callID = counter.incrementAndGet();
        new Thread(new Runnable() {
            @Override
            public void run() {
                ServerConnection.get("person-login-relations?byUsername="+username,null, new JsonHttpResponseHandler(){
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, JSONObject response){
                        try {
                            callResults.put(callID, new CallResult(Login.parseFromJson(response)));
                            System.out.println(callResults.get(callID));

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });


            }
        })   .start();

        while(callResults.get(callID) == null){
            //wait
        }
        return (Login) callResults.remove(callID).content;
    }

Это, похоже, решило проблему, которую я описал здесь, из-за цикла, блокирующего запрос. Я предполагаю, что это может быть потому, что запрос или обработка ответа могли быть обработаны тем же потоком, который содержал цикл и, таким образом, ожидал завершения цикла. Хотя я не совсем уверен, тем более, что раньше я использовал асинхронные запросы, которые обрабатывались в потоке вне моего контроля

0 голосов
/ 01 мая 2019

Цикл while, вероятно, будет максимально загружать ваш процессор и ограничивать все остальные операции. В таких циклах ожидания вы всегда должны вводить некоторую задержку, даже 100-10 мс достаточно.

Просто вызовите Thread.sleep(100); в вашем цикле (и где-нибудь обработайте исключение InterruptedException).

Так, например:

   while(callResults.get(callID) == null){
       try {
           Thread.sleep(100);
       } catch (InterruptedException e) {
           return null; // Return null or just throw a RuntimeException. You can be pretty sure that this will never be called unless your app gets closed or your thread intentionally interrupted.
       }
       System.out.print(".");
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...