我有一系列异步操作
private void doSomething(){
get("/something", new Callback(){
void onComplete(String data){
updateUi(something, data);
doSomethingElse();
}
});
}
private void doSomethingElse(){
get("/something/else", new Callback(){
void onComplete(String data){
updateUi(somethingElse, data);
doYetAnotherThing();
}
});
}
private void doYetAnotherThing(){
get("/yet/another/thing", new Callback(){
void onComplete(String data){
updateUi(yetAnotherThing, data);
allDone();
}
});
}
这几乎没有问题:
我已查看以下选项以缓解此问题:
ExecuterService#invokeAll
- 我不知道如何在不阻止的情况下使用此解决方案。ListenableFutures
及其transform
方法。我在互联网坚果周围的几个地方看到了这一点,老实说我不知道这会如何解决我的问题。所以,问题是:在Java中链接一系列异步调用的好方法是什么?寻找适用于Java 7的解决方案,因为我需要这个Android应用程序。
答案 0 :(得分:4)
对于遇到此问题的实际意图和用例,肯定会涉及一些猜测。此外,还不完全清楚something
,somethingElse
和yetAnotherThing
是什么(它们来自哪里以及应该去哪里)。
但是,根据您提供的信息,以及answer by slartidan的补充(或者更确切地说是扩展或概括):您在那里描绘的这些虚拟调用之间的区别似乎是
String
方法get
参数
Callback
您可以将这些部分分解出来:String
参数和Callback
可以作为参数传递给创建Callable
的常规方法。可以通过将这些Callable
对象以适当的顺序放入列表中来定义调用的顺序,并使用单线程执行程序服务执行它们。
正如您在本示例的main
方法中所看到的,然后可以相当容易地配置调用序列:
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChainedAsyncTest {
public static void main(String[] args) throws InterruptedException {
ChainedAsyncTest t = new ChainedAsyncTest();
ExecutorService e = Executors.newFixedThreadPool(1);
e.invokeAll(Arrays.asList(
t.call("/something", t.somethingCallback),
t.call("/something/else", t.somethingElseCallback),
t.call("/yet/another/thing", t.yetAnotherThingCallback),
t.allDone()));
}
private Callback somethingCallback = new Callback() {
@Override
public void onComplete(String data) {
updateUi("something", data);
}
};
private Callback somethingElseCallback = new Callback() {
@Override
public void onComplete(String data) {
updateUi("somethingElse", data);
}
};
private Callback yetAnotherThingCallback = new Callback() {
@Override
public void onComplete(String data) {
updateUi("yetAnotherThing", data);
}
};
private Callable<Void> call(
final String key, final Callback callback) {
return new Callable<Void>() {
@Override
public Void call() {
get(key, callback);
return null;
}
};
}
private Callable<Void> allDone() {
return new Callable<Void>() {
@Override
public Void call() {
System.out.println("allDone");
return null;
}
};
}
interface Callback
{
void onComplete(String data);
}
private void get(String string, Callback callback) {
System.out.println("Get "+string);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.onComplete("result of "+string);
}
private void updateUi(String string, String data) {
System.out.println("UpdateUI of "+string+" with "+data);
}
}
(该示例使用invokeAll
,它会阻塞直到所有任务都已执行。这可以通过不同方式解决,以便在呼叫站点真正无阻塞。主要思想是创建任务列表,这些都是通过相同的方法调用创建的)
答案 1 :(得分:1)
狡猾的想法:您可以将链式调用定义为方法参数,以使您的方法可重用。这是我的示例代码:
public class Scribble {
final Callback step1 = new Callback() {
void onComplete(String string) {
doSomethingElse(step2);
};
};
final Callback step2 = new Callback() {
void onComplete(String string) {
doYetAnotherThing(step3);
};
};
final Callback step3 = new Callback() {
void onComplete(String string) {
allDone();
}
};
private void start() {
doSomething(step1);
}
private void doSomething(final Callback externalCallback) {
get("/something", new Callback() {
void onComplete(String data) {
updateUi(something, data);
externalCallback.onComplete(data);
}
});
}
private void doSomethingElse(final Callback externalCallback) {
get("/something/else", new Callback() {
void onComplete(String data) {
updateUi(somethingElse, data);
externalCallback.onComplete(data);
}
});
}
private void doYetAnotherThing(final Callback externalCallback) {
get("/yet/another/thing", new Callback() {
void onComplete(String data) {
updateUi(yetAnotherThing, data);
externalCallback.onComplete(data);
}
});
}
// - the code below is only to make everything compilable -
public class Callback {
void onComplete(String string) {
}
}
private Object something;
protected Object somethingElse;
protected Object yetAnotherThing;
protected void allDone() {
System.out.println("Scribble.allDone()");
}
protected void updateUi(Object yetAnotherThing2, String data) {
System.out.println("Scribble.updateUi()"+data);
}
private void get(String string, Callback callback) {
System.out.println("get "+string);
callback.onComplete(string);
}
public static void main(String[] args) {
new Scribble().start();
}
}
答案 2 :(得分:1)
我完全支持已批准的答案,但是当我开始在异步操作链中添加条件逻辑时,我也会为这些类型的问题创建一些东西。我最近把它发酵成一个简单的库(jasync-driver)。
以下是您如何连接示例的方法。如您所见,每个任务都不了解后面的任务。与批准的答案相反,任务的链接是通过简单的同步(...查找)方法体而不是列表来完成的。
public void doChainedLogic() {
final AsyncTask<Void, Void> doSomething = new AsyncTask<Void, Void>() {
@Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something", new Callback() {
public void onComplete(String data) {
updateUi(something, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doSomethingElse = new AsyncTask<Void, Void>() {
@Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something/else", new Callback() {
public void onComplete(String data) {
updateUi(somethingElse, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doYetAnotherThing = new AsyncTask<Void, Void>() {
@Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/yet/another/thing", new Callback() {
public void onComplete(String data) {
updateUi(yetAnotherThing, data);
resultHandler.reportComplete();
}
});
}
};
// This looks synchronous, but behind the scenes JasyncDriver is
// re-executing the body and skipping items already executed.
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
driver.execute(doSomethingElse);
driver.execute(doYetAnotherThing);
}
});
}
现在,这是对示例的一个调整,其中包括一些取决于异步结果的条件逻辑:
final AsyncTask<Void, String> checkSomething = new AsyncTask<Void, String>() {
@Override
public void run(Void arg, final ResultHandler<String> resultHandler) {
get("/check/something", new Callback() {
public void onComplete(String data) {
resultHandler.reportComplete(data);
}
});
}
};
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
if ("foobar".equals(driver.execute(checkSomething))) {
driver.execute(doSomethingElse);
}
driver.execute(doYetAnotherThing);
}
});
如您所见,异步条件逻辑就像编写标准if语句一样简单。