注意@Matthews答案是正确的但是如果你在另一个线程并且在没有互联网时你进行了一次凌空调用, your error callback will be called on the main thread, but the thread you are on will be blocked FOREVER. (因此如果该线程是一个IntentService,你将永远无法向它发送另一条消息,你的服务将会基本上死了) .
//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...
}
一种方法是覆盖默认方式RequestQueue is created,其中使用替代构造函数,注入 ResponseDelivery ,它从当前线程而不是主线程生成 . 但是,我没有调查过这个问题 .
1
我使用锁来实现这种效果现在我想知道它是否正确我的方式任何人想要评论?
// 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();
}
}
6 回答
看起来有可能与Volley的
RequestFuture
级 . 例如,要创建同步JSON HTTP GET请求,您可以执行以下操作:注意@Matthews答案是正确的但是如果你在另一个线程并且在没有互联网时你进行了一次凌空调用, your error callback will be called on the main thread, but the thread you are on will be blocked FOREVER. (因此如果该线程是一个IntentService,你将永远无法向它发送另一条消息,你的服务将会基本上死了) .
使用具有超时
future.get(30, TimeUnit.SECONDS)
的get()
版本并捕获错误以退出线程 .要匹配@Mathews答案:
下面我将它包装在一个方法中并使用不同的请求:
可能建议使用Futures,但如果出于任何原因你不想做,而不是烹饪你自己的同步阻塞事物,你应该使用
java.util.concurrent.CountDownLatch
. 所以这会像这样工作..由于人们似乎真的试图这样做并遇到一些麻烦我决定我实际上提供了一个正在使用的"real life"工作样本 . 这是https://github.com/timolehto/SynchronousVolleySample
现在即使解决方案有效,它也有一些局限性 . 最重要的是,您无法在主UI线程上调用它 . Volley确实在后台执行请求,但默认情况下,Volley使用应用程序的主
Looper
来发送响应 . 当主UI线程正在等待响应时,这会导致死锁,但Looper
在处理传递之前正在等待onCreate
完成 . 如果你真的想要这样做,你可以,而不是静态帮助器方法,实例化你自己的RequestQueue
传递它自己的ExecutorDelivery
绑定到Handler
使用Looper
绑定到主UI线程的不同线程 .作为对@Blundells和@Mathews答案的补充观察,我不确定除了Volley的主要线程之外还有任何电话 .
The Source
看看RequestQueue implementation似乎
RequestQueue
正在使用NetworkDispatcher
执行请求而ResponseDelivery
正在传递结果(ResponseDelivery
被注入NetworkDispatcher
) .ResponseDelivery
依次使用主线程中的Handler
spawn创建(在RequestQueue
实现中的第112行附近) .在NetworkDispatcher implementation中关于第135行的某处,似乎也成功的结果通过与任何错误相同的
ResponseDelivery
传递 . 再次; aResponseDelivery
基于主线程的Handler
spawn .Rationale
对于从
IntentService
发出请求的用例,可以假设服务的线程应该阻塞,直到我们得到Volley的响应(以保证生存的运行时范围来处理结果) .Suggested solutions
一种方法是覆盖默认方式RequestQueue is created,其中使用替代构造函数,注入
ResponseDelivery
,它从当前线程而不是主线程生成 . 但是,我没有调查过这个问题 .我使用锁来实现这种效果现在我想知道它是否正确我的方式任何人想要评论?
我想在Matthew接受的答案中添加一些内容 . 虽然
RequestFuture
似乎可以从您创建它的线程进行同步调用,但事实并非如此 . 而是在后台线程上执行调用 .根据我在浏览库后的理解,
RequestQueue
中的请求将以start()
方式调度:现在,
CacheDispatcher
和NetworkDispatcher
类都扩展了线程 . 因此,有效地生成了一个新的工作线程,用于使请求队列出列,并将响应返回给RequestFuture
内部实现的成功和错误侦听器 .虽然你的第二个目的已经实现,但你的第一个目的不是因为总是产生一个新的线程,无论你从哪个线程执行
RequestFuture
.简而言之, true synchronous request is not possible with default Volley library. 如果我错了,请纠正我 .