我正在使用 JavaFX 的 WebView
解析网站。该网站包含一堆链接 - 我需要按照给定的顺序单独打开每个链接,并从每个链接中检索一条信息。
为了确保 WebView
已加载整个网站,我正在听changed
事件WebEngine
等待newState == Worker.State.SUCCEEDED
。问题是这个调用是异步的。当我打电话webEngine.load(firstAddress);
时,代码立即返回,在加载此页面之前,我的代码将调用另一个 webEngine.load(secondAddress);
,等等。
我理解为什么这样做(为什么异步比同步更好),但我是Java初学者,我不确定这个问题的最佳解决方案是什么。我以某种方式了解多线程和其他东西,所以我已经尝试过信号量( CountDownLatch
类)。但代码卡在await
上我不确定我做错了什么。
有人可以告诉我如何以正确的方式完成它吗?也许有一些通用模式如何应对这样的场景?
我想要实现的伪代码:
WebEngine webEngine = new WebEngine();
webEngine.loadPage("http://www.something.com/list-of-cars");
webEngine.waitForThePageToLoad(); // I need an equivalent of this. In the real code, this is done asynchronously as a callback
// ... some HTML parsing or DOM traversing ...
List<String> allCarsOnTheWebsite = webEngine.getDocument()....getChildNodes()...;
// allCarsOnTheWebsite contains URLs to the pages I want to analyze
for (String url : allCarsOnTheWebsite)
{
webEngine.loadPage(url);
webEngine.waitForThePageToLoad(); // same as in line 3
String someDataImInterestedIn = webEngine.getDocument()....getChildNodes()...Value();
System.out.println(url + " : " + someDataImInterestedIn);
}
System.out.println("Done, all cars have been analyzed");
最佳答案
您应该使用在页面加载时调用的监听器,而不是阻塞直到完成。
类似于:
WebEngine webEngine = new WebEngine();
ChangeListener<State> initialListener = new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> obs, State oldState, State newState) {
if (newState == State.SUCCEEDED) {
webEngine.getLoadWorker().stateProperty().removeListener(this);
List<String> allCarsOnTheWebsite = webEngine.getDocument()... ;
loadPagesConsecutively(allCarsOnTheWebsite, webEngine);
}
}
};
webEngine.getLoadWorker().addListener(initialListener);
webEngine.loadPage("http://www.something.com/list-of-cars");
// ...
private void loadPagesConsecutively(List<String> pages, WebEngine webEngine) {
LinkedList<String> pageStack = new LinkedList<>(pages);
ChangeListener<State> nextPageListener = new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> obs, State oldState, State newState) {
if (newState == State.SUCCEEDED ) {
// process current page data
// ...
if (pageStack.isEmpty()) {
webEngine.getLoadWorker().stateProperty().removeListener(this);
} else {
// load next page:
webEngine.load(pageStack.pop());
}
}
}
};
webEngine.getLoadWorker().stateProperty().addListener(nextPageListener);
// load first page (assumes pages is not empty):
webEngine.load(pageStack.pop());
}
关于java - 同步一系列异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27494048/