내 목표는 웹 서버에서 문서를로드 한 다음 특정 콘텐츠에 대한 DOM을 구문 분석하는 것입니다. DOM을 로딩하는 것이 제 문제입니다.WebEngine 용 작업자 스레드가 완료되지 않는 이유는 무엇입니까?
javafx.scene.web.WebEngine
을 사용하려고합니다. 최종 DOM에 영향을 줄 수있는 자바 스크립트 실행을 포함하여 필요한 모든 기능을 수행 할 수있는 것처럼 보입니다.
문서를로드 할 때 RUNNING
상태에서 멈추었으며 WebEngine.getDocument()
에서 DOM에 액세스하기 전에 필요하다고 생각되는 SUCCEEDED
상태에 도달하지 못하는 것처럼 보입니다.
이것은 URL 또는 리터럴 콘텐츠 (이 최소 예에서 사용 된)에서로드하는지 여부에 관계없이 발생합니다.
누구나 내가 잘못하거나 오해 한 것을 볼 수 있습니까?
미리 도움을 청하십시오.
import java.util.concurrent.ExecutionException;
import org.w3c.dom.Document;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.embed.swing.JFXPanel;
import javafx.scene.web.WebEngine;
public class WebEngineProblem {
private static Task<WebEngine> getEngineTask() {
Task<WebEngine> task = new Task<>() {
@Override
protected WebEngine call() throws Exception {
WebEngine webEngine = new WebEngine();
final Worker<Void> loadWorker = webEngine.getLoadWorker();
loadWorker.stateProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("state:" + newValue);
if (newValue == State.SUCCEEDED) {
System.out.println("finished loading");
}
});
webEngine.loadContent("<!DOCTYPE html>\r\n" + "<html>\r\n" + "<head>\r\n" + "<meta charset=\"UTF-8\">\r\n"
+ "<title>Content Title</title>\r\n" + "</head>\r\n" + "<body>\r\n" + "<p>Body</p>\r\n" + "</body>\r\n"
+ "</html>\r\n");
State priorState = State.CANCELLED; //should never be CANCELLED
double priorWork = Double.NaN;
while (loadWorker.isRunning()) {
final double workDone = loadWorker.getWorkDone();
if (loadWorker.getState() != priorState || priorWork != workDone) {
priorState = loadWorker.stateProperty().getValue();
priorWork = workDone;
System.out.println(priorState + " " + priorWork + "/" + loadWorker.getTotalWork());
}
Thread.sleep(1000);
}
return webEngine;
}
};
return task;
}
public static void main(String[] args) {
new JFXPanel(); // Initialise the JavaFx Platform
WebEngine engine = null;
Task<WebEngine> task = getEngineTask();
try {
Platform.runLater(task);
Thread.sleep(1000);
engine = task.get(); // Never completes as always RUNNING
}
catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// This code is never reached as the content never completes loading
// It would fail as it's not on the FX thread.
Document doc = engine.getDocument();
String content = doc.getTextContent();
System.out.println(content);
}
}
작업이 백그라운드 스레드에서 실행되도록 설계되어 있습니다 : 당신은 FX 응용 프로그램 스레드에서이 작업을 실행하는
여기 예를 들어 내가 당신이하려고 생각하고있다. 'SUCCEEDED' 상태 변경은 FX 응용 프로그램 스레드에서도 발생하므로 작업이 완료 될 때까지 상태를 변경할 수 없습니다. while 루프는'loadWorker'가'RUNNING' 상태에서 벗어날 때까지는 사실상 이상한 형태의 교착 상태가 발생할 때까지 완료되지 않을 것입니다. –
확실히,'Platform.runLater() '호출은 작업이 FXApplication 쓰레드에서 실행되도록하는 방법이지만, 작업자 쓰레드는 별개이고 별개입니까? webEngine.loadContent()가 즉시 반환되므로로드가 별도의 작업자 스레드에서 발생해야합니다. "백그라운드 스레드에서 항상 로딩이 발생합니다 백그라운드 작업을 예약 한 후 로딩을 시작하는 메서드가 즉시 반환됩니다 진행률을 추적하거나 작업을 취소하려면 getLoadWorker() 메서드에서 사용할 수있는 Worker 인스턴스를 사용하십시오." https://docs.oracle.com/javase/8/javafx/api/javafx/scene/web/WebEngine.html – Dragonthoughts
작업자 스레드는 분리되어 있지만 별개이지만 작업자의 stateProperty() FX 응용 프로그램 스레드에서 발생합니다. (기본적으로이 속성은 모두 단일 스레드입니다.) 따라서 작업자 스레드의 구현에서 어딘가에 'Platform.runLater (...)'상태를 업데이트합니다. FX 응용 프로그램 스레드를 차단 한 경우 실제로는 호출 할 수 없습니다. (기본적으로 "헤드리스"모드에서 실행 중이더라도 FX 응용 프로그램 스레드를 차단해서는 안됩니다.) –