6

私はLibGDXで小さなゲームを作っています。プレーヤーのユーザー名をローカルとサーバーに保存しています。問題は、アプリケーションが呼び出しの結果を待っていないため、オンライン データベースの ID がローカルに保存されないことです。コードの全体的な流れは次のとおりです。

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

このコードでは、関数がすぐに返されるidため、変数は設定されていません。saveUserサーバー通信からの結果を処理できるように、アプリケーションがネットワーク要求の結果を待機するようにするにはどうすればよいですか?

これはのコードです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();
}

これは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;
    }
}
4

2 に答える 2

4

あなたが見ている非同期はからのものGdx.net.sendHttpRequestです。2 番目のパラメーター ( your WerewolfsResponseListener) のメソッドは、リクエストが返されるたびに呼び出されます。成功/失敗メソッドは「インライン」で呼び出されません。

このように構造化されたコールバックを処理するには、「ポーリング」または「イベント」という 2 つの基本的なアプローチがあります。

ポーリングを使用すると、メインのゲーム ループが を「チェック」しresponseListenerて、成功したか失敗したかを確認できます。(成功のケースと空の文字列を明確にするために、現在のリスナーを少し変更する必要があります。) 有効な応答が表示されたら、次のことを行うことができますuser.setId()

「イベント」を使用すると、呼び出しをコールバックuser.setId()内に置くことresponseListenerができるため、ネットワークが応答するたびに実行されます。これは、Libgdx ネット API にもう少し自然に適合します。(これは、応答リスナーがオブジェクトへの参照を必要とすることを意味しuserます。)

ネットワーク呼び出しが戻るのをインラインで「待機」することはできません。Libgdx ネットワーク API は (正しく) レンダー スレッドで無期限にブロックしたくないと想定しているため、そのように構造化されていません (リスナーは Runnable としてキューに入れられるため、実行できる最も早いのは次のレンダー コールです)。 .

于 2013-04-24T23:46:25.033 に答える
1

私はこれをどんな人にもお勧めしませんが、何かを手早く汚れた方法でテストする必要があり、絶対にブロックする必要がある場合は、これでうまくいきます。タイムアウトはないので、繰り返しになりますが、絶対的な汚れに備えてください。

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;
    }

}
于 2014-02-23T08:24:00.597 に答える