web-dev-qa-db-ja.com

Volley-ブロッキング方法でのHTTPリクエスト

最近、Google Volleyの使い方を学んでいます。高速ネットワーキングには非常に便利です。リクエストはすべてVolleyでバックグラウンドで実行されているようです。例えば:

volleyRequestQueue.add(new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, new SignUpResponseListener(), new MyErrorListener()));

上記のコードを使用して、バックグラウンドで実行するPOST呼び出しを実行できます(非ブロッキング方法)。今私の質問は:POST呼び出しをブロックする方法で行うことは可能ですか? REST呼び出しを行うためにブロッキング方法が必要なのはなぜですか?サインインなどの一部の呼び出しは、何か他のことを行う前に行う必要があるためです。

ありがとう

17
Fihop

Volleyは、RequestFuturesによるリクエストのブロックをサポートしています。通常のリクエストを作成し、そのコールバックをフューチャーリクエストとして設定します。これは、標準のJava futuresのボレーの拡張です。future.get()の呼び出しはブロックされます。

こんな感じ

RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, future, future)
volleyRequestQueue.add(request);

try {
    JSONObject response = future.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
29
Gabriel

タイムアウトと同様にInterruptedExceptionを適切に処理する明確な答えがあります。割り込みを飲み込んで続行したいのは、割り込みを使用してリクエストへの応答をキャンセルする場合のみです。

RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, future, future);
volleyRequestQueue.add(request);

try {
    JSONObject response = null;
    while (response == null) {
        try {
            response = future.get(30, TimeUnit.SECONDS); // Block thread, waiting for response, timeout after 30 seconds
        } catch (InterruptedException e) {
            // Received interrupt signal, but still don't have response
            // Restore thread's interrupted status to use higher up on the call stack
            Thread.currentThread().interrupt();
            // Continue waiting for response (unless you specifically intend to use the interrupt to cancel your request)
        }
    }
    // Do something with response, i.e.
    new SignUpResponseListener().onResponse(response);
} catch (ExecutionException e) {
    // Do something with error, i.e.
    new MyErrorListener().onErrorResponse(new VolleyError(e));
} catch (TimeoutException e) {
    // Do something with timeout, i.e.
    new MyErrorListener().onErrorResponse(new VolleyError(e));
}
4
Jeff Lockhart

Volleyリクエストの直後に何かを実行したい場合は、コールバックリスナーonSuccess(その場合はSignUpResponseListener)を使用して、そこにコードを配置します。これがベストプラクティスです。

1
Makibo

RequestFutureを動作させることができなかったので、Makiboが提案したようなコールバックリスナーを使用しました。なぜ彼が反対票を投じられたのかはわかりませんが、これはおそらく、最初のログインなどに依存するさまざまなボレーリクエストの元の一般的な問題に対する最良の解決策です。この例では、写真をアップロードしたいのですが、まずユーザーがログインしているかどうかを確認します。そうでない場合は、ログインしてから写真をアップロードする前に成功するまで待機する必要があります。すでにログインしている場合は、そのまま写真をアップロードしてください。

これが私のサンプルコードです:

// interface we'll use for listener
public interface OnLoginListener {
    public void onLogin();
}

public void uploadPhoto(final String username, final String password, final String photo_location) {
    // first setup callback listener that will be called if/when user is logged in
    OnLoginListener onLoginListener=new OnLoginListener() {
        @Override
        public void onLogin() {
            uploadPhotoLoggedIn(photo_location);
        }
    };
    // simplistic already logged in check for this example, just checking if username is null
    if (loggedInUsername==null) {
        // if it null, login and pass listener
        httpLogin(username, password, onLoginListener);
    } else {
        // if not null, already logged in so just call listener method
        onLoginListener.onLogin();
    }
}

public void httpLogin(String username, String password, final OnLoginListener onLoginListener) {
    StringRequest loginRequest = new StringRequest(Request.Method.POST, "https://www.example.com/login.php", new Response.Listener<String>() { 
        @Override
        public void onResponse(String txtResponse) {
            Log.d("STACKOVERFLOW",txtResponse);
            // call method of listener after login is successful. so uploadPhotoLoggedIn will be called now
            onLoginListener.onLogin();
        } }, 
        new Response.ErrorListener() 
        {
            @Override
            public void onErrorResponse(VolleyError error) {
                // TODO Auto-generated method stub
                Log.d("VOLLEYERROR","error => "+error.toString());
            }
        }
            ) {
    };    
    // Just getting the Volley request queue from my application class (GetApplicatio.Java), and adding request
    GetApplication.getRequestQueue().add(loginRequest);
}
1
georgiecasey

ガブリエルの答えに何か付け加えたい。 RequestFutureは、それが呼び出されたスレッドをブロックし、ユーザーの目的を果たしますが、ネットワーク要求自体はそのスレッドでは実行されません。代わりに、バックグラウンドスレッドで実行されます。

ライブラリを調べたところ、RequestQueueのリクエストはstart()メソッドでディスパッチされました。

    public void start() {
        ....
        mCacheDispatcher = new CacheDispatcher(...);
        mCacheDispatcher.start();
        ....
           NetworkDispatcher networkDispatcher = new NetworkDispatcher(...);
           networkDispatcher.start();
        ....
    }

CacheDispatcherクラスとNetworkDispatcherクラスの両方がスレッドを拡張するようになりました。したがって、事実上、リクエストキューをデキューするための新しいワーカースレッドが生成され、RequestFutureによって内部的に実装された成功およびエラーリスナーに応答が返されます。

したがって、RequestFutureを使用するために別のブロッキングスレッドを作成しても意味がありません。代わりにマキボが彼の答えで述べたように-「コールバックリスナーonSuccess(その場合はSignUpResponseListener)を使用し、そこにコードを配置します。」

1
Vignatus