Могу ли я сделать синхронный запрос с волейболом?

Представьте, что я нахожусь в службе, которая уже имеет фоновый stream. Могу ли я сделать запрос, используя залп в том же streamе, чтобы обратные вызовы происходили синхронно?

Для этого есть две причины: – Во-первых, мне не нужна другая нить, и было бы бесполезно создавать ее. – Во-вторых, если я нахожусь в ServiceIntent, выполнение streamа завершится до обратного вызова, и поэтому у меня не будет ответа от Volley. Я знаю, что могу создать свою собственную Службу, которая имеет некоторый stream с помощью runloop, которым я могу управлять, но хотелось бы иметь эту функциональность в залпе.

Спасибо!

Похоже, это возможно с classом Volley’s RequestFuture . Например, чтобы создать синхронный запрос GET HTTP GET, вы можете сделать следующее:

 RequestFuture future = RequestFuture.newFuture(); JsonObjectRequest request = new JsonObjectRequest(URL, new JSONObject(), future, future); requestQueue.add(request); try { JSONObject response = future.get(); // this will block } catch (InterruptedException e) { // exception handling } catch (ExecutionException e) { // exception handling } 

Примечание. Ответ @Matthews правильный, но если вы находитесь в другом streamе, и вы вызываете вызов волейбола, когда у вас нет интернета, ваш обратный вызов будет вызываться в основном streamе, но stream, на котором вы находитесь, будет заблокирован FOREVER. (Поэтому, если этот stream является IntentService, вы никогда не сможете отправить ему другое сообщение, и ваша служба будет в основном мертвой).

Используйте версию get() которая имеет timeout future.get(30, TimeUnit.SECONDS) и поймает ошибку, чтобы выйти из streamа.

Чтобы ответить @Mathews, ответьте:

  try { return future.get(30, TimeUnit.SECONDS); } catch (InterruptedException e) { // exception handling } catch (ExecutionException e) { // exception handling } catch (TimeoutException e) { // exception handling } 

Ниже я завернул его в метод и использовал другой запрос:

  /** * Runs a blocking Volley request * * @param method get/put/post etc * @param url endpoint * @param errorListener handles errors * @return the input stream result or exception: NOTE returns null once the onErrorResponse listener has been called */ public InputStream runInputStreamRequest(int method, String url, Response.ErrorListener errorListener) { RequestFuture future = RequestFuture.newFuture(); InputStreamRequest request = new InputStreamRequest(method, url, future, errorListener); getQueue().add(request); try { return future.get(REQUEST_TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException e) { Log.e("Retrieve cards api call interrupted.", e); errorListener.onErrorResponse(new VolleyError(e)); } catch (ExecutionException e) { Log.e("Retrieve cards api call failed.", e); errorListener.onErrorResponse(new VolleyError(e)); } catch (TimeoutException e) { Log.e("Retrieve cards api call timed out.", e); errorListener.onErrorResponse(new VolleyError(e)); } return null; } 

Вероятно, рекомендуется использовать Фьючерсы, но если по какой-либо причине вы не хотите, вместо того, чтобы готовить собственную синхронизированную блокировку, вы должны использовать java.util.concurrent.CountDownLatch . Так что это будет так.

 //I'm running this in an instrumentation test, in real life you'd ofc obtain the context differently... final Context context = InstrumentationRegistry.getTargetContext(); final RequestQueue queue = Volley.newRequestQueue(context); final CountDownLatch countDownLatch = new CountDownLatch(1); final Object[] responseHolder = new Object[1]; final StringRequest stringRequest = new StringRequest(Request.Method.GET, "http://google.com", new Response.Listener() { @Override public void onResponse(String response) { responseHolder[0] = response; countDownLatch.countDown(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { responseHolder[0] = error; countDownLatch.countDown(); } }); queue.add(stringRequest); try { countDownLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } if (responseHolder[0] instanceof VolleyError) { final VolleyError volleyError = (VolleyError) responseHolder[0]; //TODO: Handle error... } else { final String response = (String) responseHolder[0]; //TODO: Handle response... } 

В качестве дополнительного наблюдения как для ответов @Blundells, так и для @Mathews я не уверен, что любой вызов доставляется ни к чему, кроме основного streamа Volley.

Источник

RequestQueue реализацию RequestQueue кажется, что RequestQueue использует NetworkDispatcher для выполнения запроса и ResponseDelivery для доставки результата (доставка ResponseDelivery вставляется в NetworkDispatcher ). В ResponseDelivery создается с помощью Handler из основного streamа (где-то вокруг строки 112 в реализации RequestQueue ).

Где-то около строки 135 в реализации NetworkDispatcher похоже, и успешные результаты доставляются через ту же ResponseDelivery что и любые ошибки. Еще раз; a ResponseDelivery на основе Handler икры из основного streamа.

обоснование

Для прецедента, в котором должен быть сделан запрос от IntentService , справедливо предположить, что stream службы должен блокироваться до тех пор, пока у нас не будет ответа от Volley (чтобы гарантировать реальную область выполнения для обработки результата).

Предлагаемые решения

Один из подходов заключался бы в переопределении способа по RequestQueue , создаваемого RequestQueue , где вместо этого используется альтернативный конструктор, который вводит ResponseDelivery которая возникает из текущего streamа, а не из основного streamа. Однако я не исследовал последствия этого.

Я использую блокировку для достижения этого эффекта, теперь им интересно, правильно ли он хочет, чтобы кто-то захотел прокомментировать?

 // as a field of the class where i wan't to do the synchronous `volley` call Object mLock = new Object(); // need to have the error and success listeners notifyin final boolean[] finished = {false}; Response.Listener> responseListener = new Response.Listener>() { @Override public void onResponse(ArrayList response) { synchronized (mLock) { System.out.println(); finished[0] = true; mLock.notify(); } } }; Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { synchronized (mLock) { System.out.println(); finished[0] = true; System.out.println(); mLock.notify(); } } }; // after adding the Request to the volley queue synchronized (mLock) { try { while(!finished[0]) { mLock.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } 

Я хочу добавить что-то к принятому ответом Мэтью. Хотя RequestFuture может показаться синхронным вызовом из streamа, который вы создали, он этого не делает. Вместо этого вызов выполняется в фоновом streamе.

Из того, что я понимаю после прохождения библиотеки, запросы в RequestQueue отправляются в методе start() :

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

Теперь CacheDispatcher и NetworkDispatcher расширяют stream. Таким образом, создается новый рабочий stream для отбрасывания очереди запросов, и ответ возвращается RequestFuture успеха и ошибок, реализованным внутри RequestFuture .

Хотя ваша вторая цель достигнута, но ваша первая цель заключается не в том, что новый stream всегда порожден, независимо от того, какой stream вы выполняете RequestFuture .

Короче говоря, истинный синхронный запрос невозможен с помощью библиотеки волейбола по умолчанию. Поправьте меня, если я ошибаюсь.

  • Как исправить android.os.NetworkOnMainThreadException?
  • Как проверить имя сертификата и псевдоним в файлах хранилища ключей?
  • BroadcastReceiver Vs WakefulBroadcastReceiver
  • Использование активности камеры в Android
  • Загрузите файл с Android и покажите прогресс в ProgressDialog
  • Как я могу получить результаты сканирования Android Wifi в список?
  • Исходные ресурсы по сравнению с базой данных SQLite
  • почему MenuItemCompat.getActionProvider возвращает значение null?
  • Недопустимый символ в пути по индексу 16
  • Как сделать PDF в Android
  • TCP \ IP-клиент - EHOSTUNREACH (нет пути к хосту)
  • Interesting Posts
    Давайте будем гением компьютера.