Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronous responses to `Gdx.net.sendHttpRequest` in LibGDX

I'm making a small game in LibGDX. I'm saving the player's username locally as well as on a server. The problem is that the application is not waiting for the result of the call so the online database's ID is not saved locally. Here's the overall flow of the code:

//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);

in this code, the id variable is not getting set because the saveUser function is returning immediately. How can I make the application wait for the result of the network request so I can work with results from the server communication?

This is the code for 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();
}

This is the WerewolfsResponseListener class:

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;
    }
}
like image 793
Robbert Avatar asked Apr 24 '13 15:04

Robbert


1 Answers

The asynchrony you are seeing is from Gdx.net.sendHttpRequest. The methods on the second parameter (your WerewolfsResponseListener) will be invoked whenever the request comes back. The success/failure methods will not be invoked "inline".

There are two basic approaches for dealing with callbacks structured like this: "polling" or "events".

With polling, your main game loop could "check" the responseListener to see if its succeeded or failed. (You would need to modify your current listener a bit to disambiguate the success case and the empty string.) Once you see a valid response, you can then do the user.setId() and such.

With "events" then you can just put the user.setId() call inside the responseListener callback, so it will be executed whenever the network responds. This is a bit more of a natural fit to the Libgdx net API. (It does mean your response listener will need a reference to the user object.)

It is not possible to "wait" inline for the network call to return. The Libgdx network API (correctly) assumes you do not want to block indefinitely in your render thread, so its not structured for that (the listener will be queued up as a Runnable, so the earliest it can run is on the next render call).

like image 125
P.T. Avatar answered Oct 15 '22 20:10

P.T.