source

발리와 동시에 요청할 수 있습니까?

goodcode 2022. 9. 23. 00:13
반응형

발리와 동시에 요청할 수 있습니까?

내가 이미 백그라운드 스레드가 있는 서비스에 있다고 상상해 보세요.콜백이 동기적으로 이루어지도록 같은 스레드에서 발리를 사용하여 요청을 수행할 수 있습니까?

여기에는 두 가지 이유가 있습니다.

  • 첫째, 다른 스레드는 필요없고 작성하기엔 아깝습니다.
  • 둘째, 서비스 중인 경우콜백 전에 스레드 실행이 종료되므로 Balley에서 응답이 없습니다.제어할 수 있는 런루프가 있는 스레드를 가진 자체 서비스를 만들 수 있지만, 이 기능은 발리에서 사용하는 것이 좋습니다.

Balley's로 가능할 것 같아요.RequestFutureJSON HTTP GET입니다.

RequestFuture<JSONObject> 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 답변은 맞지만 인터넷이 없는 상태에서 다른 스레드에 접속하여 발리콜을 실행하면 메인 스레드에서 에러콜백이 호출됩니다만, 그 스레드가 인텐트 서비스인 경우, 그 스레드에 다른 메시지를 송신할 수 없고, 서비스는 b가 됩니다.죽은 것처럼)

의 합니다.get()이 .future.get(30, TimeUnit.SECONDS)이치노

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

Futures를 로든 원하지 에는, 하는 것이 , Futures를 사용하는 .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<String>() {
    @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...
}

사람들이 실제로 이 작업을 시도하고 문제가 생겼기 때문에 실제로 사용하고 있는 작업 샘플을 제공하기로 결정했습니다.https://github.com/timolehto/SynchronousVolleySample 입니다.

이 솔루션은 효과가 있지만 몇 가지 제한이 있습니다.가장 중요한 것은 메인 UI 스레드에서는 호출할 수 없다는 것입니다.으로 Balley는 Balley를 합니다.Looper응용 프로그램의 응답을 디스패치합니다.로 인해 메인 있기 에 교착 상태가 단, UI는 응답을 있습니다.Looper 있다onCreate배송을 처리하기 전에 완료해야 합니다., 아닌 만의 도우미 방식을 수 .RequestQueue 으로 넘기다ExecutorDelivery Handler, 「」의Looper메인 UI 스레드와 다른 스레드에 연결되어 있습니다.

코틀린 코루틴과 함께라면

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
private suspend fun request(context: Context, link : String) : String{
   return suspendCancellableCoroutine { continuation ->
      val queue = Volley.newRequestQueue(context)
      val stringRequest = StringRequest(Request.Method.GET, link,
         { response ->
            continuation.resumeWith(Result.success(response))
         },
          {
            continuation.cancel(Exception("Volley Error"))
         })

      queue.add(stringRequest)
   }
}

그리고 전화하기

CoroutineScope(Dispatchers.IO).launch {
    val response = request(CONTEXT, "https://www.google.com")
    withContext(Dispatchers.Main) {
       Toast.makeText(CONTEXT, response,Toast.LENGTH_SHORT).show()
   }
}

@Blundells와 @Mathews의 응답에 대한 보완적 관찰로서, Balley가 주요 스레드 이외에는 어떤 전화도 전달되지 않을 입니다.

소스

실장을 보면,RequestQueue요.NetworkDispatcherResponseDeliveryResponseDelivery이 됩니다.NetworkDispatcherResponseDelivery다음으로, 에 의해 작성됩니다.Handler스레드(「112」의)에서 된다.RequestQueue★★★★★★★★★★★★★★★★★★」

구현의 약 135라인에서 성공적인 결과도 같은 방법으로 전달되는 것 같습니다.ResponseDelivery에러로 간주합니다. 한 번, 다시 한 번, 한 번, 한 번.ResponseDelivery에에에 Handler사에서알알알알낳

근거

IntentServiceBalley에서 응답이 있을 때까지 서비스 스레드가 차단되어야 한다고 가정하는 것이 타당합니다(결과를 처리할 수 있는 실행 시간 범위를 보증합니다).

권장되는 해결책

한 가지 접근법은 기본 생성 방법을 재정의하는 것입니다. 여기서 대체 생성자가 대신 사용되며 이 생성자는 이 기본 생성자를 사용하여ResponseDelivery메인 스레드가 아닌 현재 스레드에서 생성됩니다.그러나 나는 이것의 함의를 조사하지 않았다.

나는 매튜가 받아들인 대답에 뭔가를 덧붙이고 싶다.한편, 「 」는, 「 」, 「 」의 사이에RequestFuture작성한 스레드에서 동기 콜을 발신하는 것처럼 보일 수 있습니다.대신 콜은 백그라운드스레드로 실행됩니다.

을 후 된 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★RequestQueuestart()★★★★

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

, 이제 둘 다CacheDispatcher ★★★★★★★★★★★★★★★★★」NetworkDispatcher이치노 위해 은 에러 리스너에 으로 구현된 및 .RequestFuture

되었지만 첫 에서 새로운 스레드를 .RequestFuture

, 기본 Bolley 라이브러리에서는 진정한 동기 요청을 수행할 수 없습니다.내가 틀렸다면 정정해 주세요.

나는 그 효과를 얻기 위해 잠금을 사용하고 있다.누군가 코멘트를 하고 싶은 내 방식이 맞는지 궁금하다.

// 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<ArrayList<Integer>> responseListener = new Response.Listener<ArrayList<Integer>>() {
                @Override
                public void onResponse(ArrayList<Integer> 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();
            }
        }

balley를 사용하여 동기화 요청을 수행할 수 있지만 다른 스레드에서 메서드를 호출해야 합니다. 그렇지 않으면 실행 중인 앱이 차단됩니다. 다음과 같습니다.

public String syncCall(){

    String URL = "http://192.168.1.35:8092/rest";
    String response = new String();



    RequestQueue requestQueue = Volley.newRequestQueue(this.getContext());

    RequestFuture<JSONObject> future = RequestFuture.newFuture();
    JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, URL, new JSONObject(), future, future);
    requestQueue.add(request);

    try {
        response = future.get().toString();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return response;


}

그 후 스레드 내의 메서드를 호출할 수 있습니다.

 Thread thread = new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        
                                        String response = syncCall();
    
                                    }
                                });
                                thread.start();

언급URL : https://stackoverflow.com/questions/16904741/can-i-do-a-synchronous-request-with-volley

반응형