3

バックグラウンドでいくつかのコードを実行し、java.util.logging.Logger を使用してそのステータスに関する情報を提供する javafx.concurrent.Task があります。このログ エントリをメイン スレッドの 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 はLogger.getLogger()毎回同じではないため、キャッシュされ、ガベージ コレクションが行われます。

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 に答える