【问题标题】:JavaFX Wait for Page to Load Before ContinuingJavaFX 在继续之前等待页面加载
【发布时间】:2015-06-01 09:15:22
【问题描述】:

我有一个为 WebView 的 WebEngine 设置新网页的方法,该方法需要等到页面完成加载才能继续使用当前方法。

基本上我想要:

MyMethod()
{
    navigateToNewUrl();
    waitForPageToLoad(); // This is the part I am struggling with
    doSomethingElse();
}

我尝试过使用 ChangeListener(),但它只会在我的方法完成执行后才会执行。我搜索了许多导致更多挫败感的术语,例如“java non-blocking wait for boolean”。最终我做到了启动新线程(以防止应用程序 GUI 锁定)并使用 CountDownTimer (而不是 Thread.join() )。下面的代码是我无数次尝试得到我想要的东西。

public static Boolean pageLoaded;
public volatile static CountDownLatch latch;

private static void TestMethod()
{
    // Set the CountDownLatch
    latch = new CountDownLatch(1);

    // Set the page loaded flag
    pageLoaded = false;

    // Navigate to new window
    myWebView.getEngine().load("https://www.google.com/");

    // Call a method, that starts a thread, that checks if the page has loaded
    WaitForPageLoaded();

    // Wait for the CountDownLatch, latch
    try { latch.await(); } catch (InterruptedException e) { /* TODO Auto-generated catch block */ e.printStackTrace(); }

    // Write result to console
    System.out.println("[pageLoaded] " + pageLoaded);
}

private static void WaitForPageLoaded()
{
    Thread thread = new Thread()
    {
        public void run()
        {
            // 120 iterations * 250 ms = 30 seconds
            for (int i = 0; i < 120; i++)
            {
                // Check if page has loaded
                if (pageLoaded == true)
                {
                    break;
                }
                else
                {
                    System.out.println("Waited " + (i*250) + " milliseconds, so far...");
                    try { Thread.sleep(250); }
                    catch (InterruptedException e) { /* TODO Auto-generated catch block */ e.printStackTrace(); }
                }
            }

            // Tell the calling method to move on with life
            latch.countDown();
        }
    }
}

在另一个 .java 文件(类)中,我有:

        // Get the WebEngine and set a listener for a state change
        WebEngine webEngine = webView.getEngine();
        webEngine.getLoadWorker().stateProperty().addListener
        (
            new ChangeListener<State>()
            {
                public void changed(@SuppressWarnings("rawtypes") ObservableValue ov, State oldState, State newState)
                {
                    if (newState == State.SUCCEEDED)
                    {
                        // Set the page loaded flag
                        OtherClassName.pageLoaded = true;
                    }
                }
            }
        );

【问题讨论】:

  • 请阅读meta.stackexchange.com/questions/66377/what-is-the-xy-problem 这看起来像是一个例子。您要在这里解决的实际问题是什么?
  • 这个问题对我来说似乎很清楚。我想确保在做任何其他事情之前页面已经加载。想象一下,代码正在运行一个导航到 URL 的 Selenium 测试。然后,一旦该页面加载到另一个 URL 或在页面上执行某些操作(无论下一个测试步骤可能是什么。在执行每个下一步之前,我需要知道页面已加载。基本上是 openAndWait()。
  • 但这与您的实际问题没有任何相似之处。等待是完全错误的方法:在上面的链接中,您询问的是您的解决方案,而不是询问您要解决的实际问题。

标签: multithreading javafx-8


【解决方案1】:

与几乎所有 UI 框架一样,JavaFX 基于事件驱动模型。在幕后,有一个循环运行(在 FX 应用程序线程中)处理事件。你不应该直接处理这个循环。

您试图通过重新创建此循环并等待条件来解决问题,而不是注册响应适当事件的处理程序。无需在线程中等待(哪个线程?没有明显的方法可以做到这一点)页面加载,您只需要响应每个页面完成加载并执行测试过程中的下一步。您可以通过在 Web 引擎的 stateProperty 上注册一个监听器来做到这一点。

所以你的结构应该是这样的

public class MyApp extends Application {

    private WebView webView ;
    private WebEngine engine ;

    // variables representing the current state of your testing process...

    @Override
    public void start(Stage primaryStage) {

        webView = new WebView();
        engine = webView.getEngine();

        engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
            if (newState == Worker.State.SUCCEEDED) {
                // new page has loaded, process:
                testMethod();
            }
        });

        // set up UI etc...

        engine.load(...); // load first page

    }

    private void testMethod() {
        // check current state, do next appropriate thing, update variables...
    }

}

这个结构完全实现了您想要做的事情 - testMethod() 被重复调用,但仅在每个页面完成加载时 - 但“等待”由框架为您管理。

【讨论】:

  • 我可能会连续多次调用TestMethod(),我想在每次退出TestMethod()之前验证页面是否已经加载。
  • 你能不能只检查网络引擎的负载工作者的状态,如果状态是RUNNING,不调用testMethod()? IE。 if (webView.getEngine().getLoadWorker().getState() != Worker.State.RUNNING) { testMethod(); }。 (任何时候有这样的问题,有比你认为的解决方案更好的方法来解决根本问题......)。
  • 我对我的问题添加了评论。但基本上,没有。我需要调用 TestMethod(),如果测试步骤是打开一个页面,那么我需要在运行下一个测试步骤之前验证加载的页面。
猜你喜欢
  • 1970-01-01
  • 2017-07-24
  • 2012-01-28
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-05
相关资源
最近更新 更多