발리와 동시에 요청할 수 있습니까?
내가 이미 백그라운드 스레드가 있는 서비스에 있다고 상상해 보세요.콜백이 동기적으로 이루어지도록 같은 스레드에서 발리를 사용하여 요청을 수행할 수 있습니까?
여기에는 두 가지 이유가 있습니다.
- 첫째, 다른 스레드는 필요없고 작성하기엔 아깝습니다.
- 둘째, 서비스 중인 경우콜백 전에 스레드 실행이 종료되므로 Balley에서 응답이 없습니다.제어할 수 있는 런루프가 있는 스레드를 가진 자체 서비스를 만들 수 있지만, 이 기능은 발리에서 사용하는 것이 좋습니다.
Balley's로 가능할 것 같아요.RequestFuture
JSON 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
요.NetworkDispatcher
를 ResponseDelivery
ResponseDelivery
이 됩니다.NetworkDispatcher
ResponseDelivery
다음으로, 에 의해 작성됩니다.Handler
스레드(「112」의)에서 된다.RequestQueue
★★★★★★★★★★★★★★★★★★」
구현의 약 135라인에서 성공적인 결과도 같은 방법으로 전달되는 것 같습니다.ResponseDelivery
에러로 간주합니다. 한 번, 다시 한 번, 한 번, 한 번.ResponseDelivery
에에에 Handler
사에서알알알알낳
근거
가 IntentService
Balley에서 응답이 있을 때까지 서비스 스레드가 차단되어야 한다고 가정하는 것이 타당합니다(결과를 처리할 수 있는 실행 시간 범위를 보증합니다).
권장되는 해결책
한 가지 접근법은 기본 생성 방법을 재정의하는 것입니다. 여기서 대체 생성자가 대신 사용되며 이 생성자는 이 기본 생성자를 사용하여ResponseDelivery
메인 스레드가 아닌 현재 스레드에서 생성됩니다.그러나 나는 이것의 함의를 조사하지 않았다.
나는 매튜가 받아들인 대답에 뭔가를 덧붙이고 싶다.한편, 「 」는, 「 」, 「 」의 사이에RequestFuture
작성한 스레드에서 동기 콜을 발신하는 것처럼 보일 수 있습니다.대신 콜은 백그라운드스레드로 실행됩니다.
을 후 된 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★RequestQueue
start()
★★★★
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
'source' 카테고리의 다른 글
마리아에서 메타 개체 데이터 숨기기nodejs 사용 시 DB (0) | 2022.09.23 |
---|---|
Windows WSL2에서 Ubuntu의 MariaDB에 있는 INSERT INTO ...에 삽입하면 일부 열의 데이터가 손상됩니다. (0) | 2022.09.23 |
왜 C 프로그래머들은 기본 타입의 이름을 바꾸기 위해 typedefs를 사용하는가? (0) | 2022.09.23 |
php의 print_r()에 해당하는 것은 무엇입니까? (0) | 2022.09.23 |
바이너리 조회를 사용하면 어떤 효과가 있습니까? (0) | 2022.09.23 |