Я переписываю некоторые части приложения для Android, чтобы вызвать REST-сервер, который я написал на Java, с использованием Spring-Boot Framework.
Подводя итог, скажем, в приложении функция A вызывает функцию B в моем MainController (который должен управлять связью клиент-сервер). Вызовы функции B (с несколькими дополнительными шагами) вызывают мой сервер. Когда функция B выполняет вызов, она использует анонимный внутренний класс, переопределяющий метод, чтобы определить, как обрабатывать ответ. Я изо всех сил пытаюсь получить этот ответ от анонимного внутреннего класса к функции B, чтобы его можно было вернуть функции A. К сожалению, задействована некоторая асинхронность, просто чтобы сделать вещи более интересными.
Моя первая попытка состояла в том, чтобы использовать карту, которая хранит результат вызова с уникальным идентификатором, чтобы сделать его доступным за пределами внутреннего класса. Теоретически работает довольно хорошо, но рушится из-за асинхронности.
Во-вторых, я прямо добавил цикл, который должен ждать, пока результат будет помещен в карту, прежде чем продолжить, чтобы убедиться, что есть что вернуть.
Каким-то образом цикл не выполняется должным образом (я считаю), и когда я использую цикл, вызов моего сервера никогда не завершается (что он и делает, когда цикла нет)
См. следующий код
Клиент: MainController
class MainController
{
private final AtomicLong counter;
private final HashMap<Long, Object> callResults;
public MainController(){
counter = new AtomicLong();
callResults = new HashMap<>();
}
public Login getLoginByUsername(String username)
{
long callID = counter.incrementAndGet();
System.out.println("Start call");
ServerConnection.get("myURL",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){
System.out.print(".");
}
System.out.println("waiting over, return result:");
System.out.println(callResults.get(callID));
//return (Login) callResults.remove(callID).content;
return null;
}
}
Клиент: Серверное соединение
import com.loopj.android.http.*;
import cz.msebera.android.httpclient.HttpEntity;
public class ServerConnection {
private static final String BASE_URL = "http://1.3.3.7:8080/";
private static AsyncHttpClient client = new AsyncHttpClient();
public static void get(String url, RequestParams params, JsonHttpResponseHandler responseHandler) {
client.get(BASE_URL+url, params, responseHandler);
}
}
Вот что я знаю:
предполагаемый ответ придет в конце концов. Когда я не использую цикл для ожидания и просто возвращаю значение null, консоль будет отображать сообщения «Вызов выполнен успешно, введите результат:» и идентификатор объекта.
При использовании цикла while ближе к концу он никогда не печатает "." - просто ничего не делает. Я знаю, что приложение все еще работает, потому что AndroidStudio постоянно сообщает мне о распределении пространства.
Попытка применить шаблон наблюдателя может полностью выйти за рамки. Мне пришлось бы очень глубоко копаться в клиентском коде, который я бы предпочел не трогать. Честно говоря, с кодом, который мне предоставили, не так-то просто работать.
Я предполагаю, что это проблема: цикл предотвращает выполнение асинхронного REST-вызова, что делает невозможным его завершение.
Мой вопрос: A) Как я могу вернуть Login-Object, который я получил от сервера, в функцию, которая в первую очередь вызвала функцию MainController.getLoginByUsername?
Б) Что происходит с циклом while, который я пытался использовать для ожидания? Почему тело (print(".");
) не будет выполнено и, что более важно, почему оно останавливает выполнение/завершение формы REST-вызова?
(также не стесняйтесь оставлять отзывы о моем стиле публикации, я впервые задаю вопрос здесь)
Изменить: добавлен вопрос B, может быть проще найти быстрое решение
Изменить в UPDATE: Извините, что не сделал это достаточно ясным: любое предложение, которое требует от меня адаптации вызывающей функции (например, шаблоны Observer-Patterns, такие как Livedata
или Rxjava
, или другие действительно хорошие предложения, предоставленные Лео Пелозо) невозможны. Я проверил, по крайней мере, предложение Лео Пелозоса, и базовый код просто не позволяет этого. Я теряю доступ к параметрам и больше не могу использовать возврат функции. Я знаю, что лучше всего было бы переработать базовую систему, но сейчас это просто выходит за рамки...