3

我有一个 javafx.concurrent.Task 在后台运行一些代码并使用 java.util.logging.Logger 来提供有关其状态的信息。我需要在主线程的 UI 中显示此日志条目。我怎样才能做到这一点?

这是我制作的一个简单的玩具项目,用于解决上下文中的问题

@Override
public void start(Stage primaryStage) {


    ListView<String> list = new ListView<>();
    final ObservableList<String> items =FXCollections.observableArrayList ();
    list.setItems(items);

    Task<String> task = new Task<String>() {

        @Override
        protected String call() throws Exception {
            doStuff();
            return "yey";
        }
    };

    new Thread(task).start();



    Scene scene = new Scene(list, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

private void doStuff() {
    for (int i=0;i<10;i++) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger("LoggerUI").log(Level.INFO, "error");
        }
        Logger.getLogger("LoggerUI").log(Level.SEVERE, "whatever");
    }

[...]
}

我试过这个,但它不起作用

public class LoggerUI extends Application {

@Override
public void start(Stage primaryStage) {
    System.out.println("UI"+ Thread.currentThread().getId());


    ListView<String> list = new ListView<>();
    final ObservableList<String> items =FXCollections.observableArrayList ();
    list.setItems(items);

    Logger.getLogger("LoggerUI").addHandler(new Handler() {

        @Override
        public void publish(LogRecord lr) {
            System.out.println("publish()"+ Thread.currentThread().getId());

            items.add(lr.getMessage());
        }

        @Override
        public void flush() {
            System.out.println("flush");
        }

        @Override
        public void close() throws SecurityException {
            System.out.println("close");

        }
    });

    Task<String> task = new Task<String>() {

        @Override
        protected String call() throws Exception {
            doStuff();
            return "yey";
        }
    };

    new Thread(task).start();



    Scene scene = new Scene(list, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

private void doStuff() {

    System.out.println("doStuff()"+ Thread.currentThread().getId());
    for (int i=0;i<300;i++) {
        final int j =i;
        try {
            Thread.sleep(30);
        } catch (InterruptedException ex) {

            Logger.getLogger("LoggerUI").log(Level.INFO, "error");
        }

        Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    System.out.println("runLater()"+ Thread.currentThread().getId());
                    Logger.getLogger("LoggerUI").log(Level.SEVERE, "whatever" +j);
                }
            });
    }

   [..]

}
}

它显示前 20-30 个条目,然后停止更新 UI

4

1 回答 1

2

更新:这实际上不是 JavaFX 问题,而是 java 日志记录的问题。

将 Logger 存储到变量中,因为Logger.getLogger()每次返回的 Logger 都不相同,它们被缓存,垃圾收集和填充。

private Logger logger = Logger.getLogger("LoggerUI");

并使用如下:

logger.addHandler(new Handler() { ... });

logger.log(Level.SEVERE, "whatever" +j);

另外,我建议将Platform.runLater()调用移至publish()方法,以便您的记录器可以从任何线程工作。

于 2012-09-09T20:06:34.410 回答