java - 应用程序 Activity 期间发生应用程序挂起或 "Not on FX application thread"

标签 java javafx

应用程序会对游戏 handle 上发生的操作使用react。当按下按钮时,用户界面上会发生一些事情。但我遇到了应用程序挂起或“java.lang.IllegalStateException:不在 FX 应用程序线程上”异常的问题。

为了修复它,我尝试了以下方法:Platform.runLater()Task 使用。但这并没有帮助。

这是问题代码:

public class GamepadUI extends Application{

    private static final int WIDTH = 300;
    private static final int HEIGHT = 213;

    private Pane root = new Pane();
    private ImageView iv1 = new ImageView();

    private boolean isXPressed = false;

    @Override
    public void start(Stage stage) throws Exception {
        initGUI(root);

        Scene scene = new Scene(root, WIDTH, HEIGHT);
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
    }

    public void pressBtn() {
        if(!isXPressed) {
            iv1.setVisible(true);
            isXPressed = true;
        }
    }

    public void releaseBtn() {
        if(isXPressed) {
            iv1.setVisible(false);
            isXPressed = false;
        }
    }

    private void initGUI(final Pane root) {
        Image image = new Image(Props.BUTTON);
        iv1.setImage(image);
        iv1.setLayoutX(198);
        iv1.setLayoutY(48);
        iv1.setVisible(false);
        root.getChildren().add(iv1);

        runTask();
    }

    public void runTask() {
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                initStubGamepad();
                return null;
            }
        };

        new Thread(task).start();
    }

    public static void main(String[] args) {
        launch(args);
    }

    public void initStubGamepad() {
        Random rnd = new Random();
        try {
            while (true) {
                if (rnd.nextInt(30) == 3) {
                    pressBtn();
                } else if (rnd.nextInt(30) == 7) {
                    releaseBtn();
                }
            }
        } catch (Exception ex) {
            System.out.println("Exception: " + ex);
        }
    }
}

initStubGamepad() 模拟游戏 handle 按钮 Activity 轮询。当用户按下任何按钮时 (rnd.nextInt(30) == 3) - UI 上会出现一个图像。当用户释放该按钮时 (rnd.nextInt(30) == 7) - 图像从 UI 中消失。

在上述情况下,发生java.lang.IllegalStateException:不在 FX 应用程序线程上。如果将 runTask() 更改为如下所示:

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        initStubGamepad();
    }
});

然后应用程序将挂起,甚至主 UI 根本不会出现,但游戏 handle Activity 仍在继续。

我想要的只是在游戏 handle 上检测到某些 Activity 时显示/隐藏不同的图像(顺便说一句,除了无限循环中的游戏 handle 轮询之外,没有办法监视游戏 handle Activity )。我做错了什么

最佳答案

说明

第一个场景中,当您使用时

Task task = new Task<Void>() {
  @Override
  protected Void call() throws Exception {
      initStubGamepad();
      return null;
  }
}

Task 上运行的 initStubGamepad() 中,您尝试更新 pressBtn()releaseBtn() 方法中的 UI 组件,这就是您面临

java.lang.IllegalStateException: Not on FX application thread

因为所有 UI 更新都必须发生在 JavaFX 线程上

第二种情况中,当您使用时

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        initStubGamepad();
    }
});

UI 没有出现,因为 initStubGamepad() 中有一个无限循环,这使得 JavaFX 应用程序线程在无限循环上运行

解决方案

当你到达这里时,你一定已经找到了解决方案。如果还没有,请尝试将 Javafx 组件的更新放在 UI 线程上。因此,不要在 Platform.runLater 中调用 initStubGamepad(),而是尝试在其中调用 pressBtn()releaseBtn()

尝试使用

while (true) {
   if (rnd.nextInt(30) == 3) {
      Platform.runLater(() -> pressBtn());            
   } else if (rnd.nextInt(30) == 7) {
       Platform.runLater(() -> releaseBtn());            
   }
}

或者您也可以使用

public void pressBtn() {
    if(!isXPressed) {
        Platform.runLater(() -> iv1.setVisible(true));
        isXPressed = true;
    }
}

关于java - 应用程序 Activity 期间发生应用程序挂起或 "Not on FX application thread",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35222886/

相关文章:

java - 如何确保枚举的状态特定于一个实例

java - JavaFX 应用程序线程的预期行为是什么

java - JavaFX 中的实时更新折线图

java - 在场景已加载/显示后,如何将复选框添加到 GridPane?

java - Java 8 Eclipse 未设置 Root 错误

java - 为什么 SVG 文件不会改变 Java 中的比例?

java - timerSchedule 不服从启动定时器设置?

java - JDBC:在 UTC 中插入时间戳

java - java中可能丢失精度错误

java - 在 MySQL 查询 Java 中使用撇号