2013-04-24 9 views
5

Tworzę małą grę w LibGDX. Zapisuję nazwę użytkownika gracza lokalnie, a także na serwerze. Problem polega na tym, że aplikacja nie czeka na wynik połączenia, więc identyfikator bazy danych online nie jest zapisywany lokalnie. Oto ogólny przepływ kodu:Synchroniczne odpowiedzi na `Gdx.net.sendHttpRequest` w LibGDX

//Create a new user object 
User user = new User(name); 

//Store the user in the online database 
NetworkService networkService = new NetworkService(); 
String id = networkService.saveUser(user); 

//Set the newly generated dbase ID on the local object 
user.setId(id); 

//Store the user locally 
game.getUserService().persist(user); 

w tym kodzie zmienna id nie jest uzyskiwanie ustawione, ponieważ funkcja saveUser wraca natychmiast. Jak mogę sprawić, aby aplikacja czekała na wynik żądania sieci, aby móc pracować z wynikami z komunikacji z serwerem?

Jest to kod dla saveUser:

public String saveUser(User user) { 
    Map<String, String> parameters = new HashMap<String, String>(); 
    parameters.put("action", "save_user"); 
    parameters.put("json", user.toJSON()); 

    HttpRequest httpGet = new HttpRequest(HttpMethods.POST); 
    httpGet.setUrl("http://localhost:8080/provisioner"); 
    httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters)); 

    WerewolfsResponseListener responseListener = new WerewolfsResponseListener(); 
    Gdx.net.sendHttpRequest (httpGet, responseListener); 
    return responseListener.getLastResponse(); 
} 

Jest to klasa WerewolfsResponseListener:

class WerewolfsResponseListener implements HttpResponseListener { 
    private String lastResponse = ""; 
    public void handleHttpResponse(HttpResponse httpResponse) { 
     System.out.println(httpResponse.getResultAsString()); 
     this.lastResponse = httpResponse.getResultAsString();  
    } 

    public void failed(Throwable t) { 
     System.out.println("Saving user failed: "+t.getMessage()); 
     this.lastResponse = null; 
    } 

    public String getLastResponse() { 
     return lastResponse; 
    } 
} 
+1

Co to jest "NetworkService"? To nie jest część Libgdxu, którą widzę. Każda asynchronia, którą widzisz, jest właściwością kodu wewnątrz 'saveUser', ponieważ metody Java są zawsze synchroniczne, więc będziesz musiał rozwinąć to. –

+0

Zobacz edycję kodu. – Robbert

Odpowiedz

4

asynchrony widzisz jest od Gdx.net.sendHttpRequest. Metody z drugiego parametru (twoje WerewolfsResponseListener) będą wywoływane zawsze, gdy żądanie wróci. Metody sukcesu/niepowodzenia będą wywoływane "inline".

Istnieją dwa podstawowe podejścia do obsługi wywołań zwrotnych zorganizowanych w następujący sposób: "odpytywanie" lub "zdarzenia".

Dzięki odpytywaniu główna pętla gry może "sprawdzić" wartość responseListener, aby sprawdzić, czy zakończyła się pomyślnie, czy nie. (Będziesz musiał nieco zmodyfikować bieżącego słuchacza, aby rozróżnić przypadek sukcesu i pusty ciąg znaków.) Gdy zobaczysz poprawną odpowiedź, możesz wykonać user.setId() i tym podobne.

Po "zdarzeniach" można po prostu umieścić wywołanie user.setId() wewnątrz wywołania zwrotnego responseListener, więc będzie ono wykonywane za każdym razem, gdy sieć odpowie. Jest to bardziej naturalne dopasowanie do interfejsu API sieci Libgdx. (Oznacza to, że detektor odpowiedzi będzie potrzebował odwołania do obiektu user.)

Nie można "czekać" w linii, aby połączenie sieciowe powróciło. Interfejs API sieci Libgdx (poprawnie) zakłada, że ​​nie chcesz blokować w nieskończoność w wątku renderowania, więc nie ma do tego struktury (słuchacz zostanie ustawiony w kolejce jako RunOble, więc najwcześniej, jaki może uruchomić, jest w trakcie następnego wywołania renderowania) .

+0

OK. Po prostu zaktualizuję lokalny obiekt użytkownika po wywołaniu funkcji zwrotnej responseListener. Dzięki! – Robbert

1

Nie poleciłbym tego żadnemu człowiekowi, ale jeśli trzeba przetestować coś w sposób szybki i brudny i absolutnie musi być blok, to zadziała. Nie ma limitu czasu, więc ponownie przygotuj się na absolutny brud:

long wait = 10; 
while(!listener.isDone()) 
{ 
    Gdx.app.log("Net", "Waiting for response"); 
    try 
    { 
     Thread.sleep(wait *= 2); 
    } 
    catch (InterruptedException e) 
    { 
     e.printStackTrace(); 
    } 
} 

public static class BlockingResponseListener implements HttpResponseListener 
{ 
    private String data; 
    private boolean done = false; 
    private boolean succeeded = false; 

    @Override 
    public void handleHttpResponse(HttpResponse httpResponse) 
    { 
     Gdx.app.log("Net", "response code was "+httpResponse.getStatus().getStatusCode()); 
     data = httpResponse.getResultAsString(); 
     succeeded = true; 
     done = true; 
    } 

    @Override 
    public void failed(Throwable t) 
    { 
     done = true; 
     succeeded = false; 
     Gdx.app.log("Net", "Failed due to exception ["+t.getMessage()+"]"); 
    } 

    public boolean succeeded() 
    { 
     return succeeded; 
    } 

    public boolean isDone() 
    { 
     return done; 
    } 

    public String getData() 
    { 
     return data; 
    } 

}