我有以下代码,它是异步执行的。我想让它同步,以便遵循一些逻辑流程,但我无法弄清楚如何。
您将看到scanning
设置为true
以指示该方法仍然有效,在开始时 - 然后我发起findPrinters(...)
命令 - 这包含运行的DiscoveryHandler异步 - 每次发现一个项目时都会调用foundPrinter()
。 discoveryFinished()
是成功完成发现过程的时间,并且每当发生错误时都会调用discoveryError(...)
。
在我想从此方法返回之前,我依赖于在DiscoveryHandler中设置的内容。因此,为什么我下面有while (scanning)
。但这对我来说就像是黑客,而不是正确的做事方式。我无法让wait()
和notify()
工作。有人能告诉我这样做的正确方法是什么?
private boolean findPrinter(final Context ctx) {
try {
scanning = true;
BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() {
public void foundPrinter(DiscoveredPrinter device) {
if (device instanceof DiscoveredPrinterBluetooth) {
DiscoveredPrinterBluetooth btDevice = (DiscoveredPrinterBluetooth) device;
if (btDevice.friendlyName.startsWith("XXXX")) {
try {
connection = new BluetoothConnection(btDevice.address);
connection.open();
if (connection.isConnected()) {
address = btDevice.address;
}
} catch (Exception ex) {
}
}
}
}
public void discoveryFinished() {
scanning = false;
}
public void discoveryError(String arg0) {
scanning = false;
}
});
} catch (Exception ex) {
}
while (scanning) {}
return false;
}
答案 0 :(得分:3)
您可以使用CountdownLatch
执行此操作,java.util.concurrent
可能是private boolean findPrinter(final Context ctx) {
final CountdownLatch latch = new CountdownLatch(1);
final boolean[] result = {false};
...
BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() {
...
public void discoveryFinished() {
result[0] = true;
latch.countDown();
}
public void discoveryError(String arg0) {
result[0] = false;
latch.countDown();
}
...
}
// before final return
// wait for 10 seconds for the response
latch.await(10, TimeUnit.SECONDS);
//return the result, it will return false when there is timeout
return result[0];
}
中最轻的同步原语:
{{1}}
答案 1 :(得分:2)
有很多方法可以做到这一点,wait()/notify()
可能不是最好的,因为你可能想从异步方法中返回一些内容。因此我建议使用像BlockingQueue
这样的东西。以下是如何执行此操作的简化示例:
private boolean findPrinter(final Context ctx) {
final BlockingQueue<?> asyncResult = new SynchronousQueue<?>();
try {
BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() {
public void foundPrinter(DiscoveredPrinter device) {
if (device instanceof DiscoveredPrinterBluetooth) {
DiscoveredPrinterBluetooth btDevice = (DiscoveredPrinterBluetooth) device;
if (btDevice.friendlyName.startsWith("XXXX")) {
try {
connection = new BluetoothConnection(btDevice.address);
connection.open();
if (connection.isConnected()) {
address = btDevice.address;
}
} catch (Exception ex) {
}
}
}
}
public void discoveryFinished() {
asyncResult.put(true);
}
public void discoveryError(String arg0) {
asyncResult.put(arg0);
}
});
} catch (Exception ex) {
}
Object result = asyncResult.take();
if (result instanceof Boolean) {
return (Boolean) result;
} else if (result instanceof String) {
logError((String) result);
}
return false;
}
这里使用SynchronousQueue
的一个问题是,如果多次调用discoveryFinished()/discoveryError()
,那么异步执行代码的线程将永远阻塞,因为SynchronousQueue
假设确实存在每个take()
一个put()
,如果put()
没有相应的take()
,则会阻止,反之亦然。因此,如果在您的情况下可以多次调用这些方法,您可能会使用不同类型的BlockingQueue
代替documentation。