JavaFX中的动画使用RxJava而不阻止GUI

时间:2017-08-26 17:06:44

标签: java javafx rx-java

这是一个简单的类,它使用冒泡排序对List Integer进行排序,并将每次迭代的结果从RxJava库推送到Subject,但有一些延迟。

public class Sorter {
    private PublishSubject<List<Integer>> subject = PublishSubject.create();

    public void bubbleSort(int delay) throws InterruptedException {
        List<Integer> ints = randomIntegers(0,200,10);
        for (int i = 0; i < ints.size(); i++) {
            for (int j = 0; j < ints.size() - 1; j++) {
                if (ints.get(j) > ints.get(j + 1)) {
                    Collections.swap(ints, j, j + 1);
                    subject.onNext(ints);
                    Thread.sleep(delay);
                }
            }
        }
    }

    private List<Integer> randomIntegers(int origin, int bound, int limit) {
        return new Random()
                .ints(origin, bound)
                .limit(limit)
                .boxed()
                .collect(Collectors.toList());
    }

    public PublishSubject<List<Integer>> getSubject() {
        return subject;
    }
}

我可以使用示例代码轻松地观察结果:

int delay = 100;
Sorter sorter = new Sorter();
PublishSubject<List<Integer>> subject = sorter.getSubject();
subject.subscribe(System.out::println);
sorter.bubbleSort(delay);
但是,我希望将迭代的结果看作移动代表数字的不同高度的矩形。我使用JavaFX。每次迭代后,我想清除应用程序窗口并重绘所有内容。

public class Main extends Application {

    private Group root;

    @Override
    public void start(Stage primaryStage) throws InterruptedException {
        root = new Group();
        Scene scene = new Scene(root, 500, 500, Color.WHITE);
        primaryStage.show();
        primaryStage.setScene(scene);

        Sorter sorter = new Sorter();
        PublishSubject<List<Integer>> subject = sorter.getSubject();
        subject.subscribe(this::drawRectangles);
        sorter.bubbleSort(100);

    }

    private void drawRectangles(List<Integer> integers) {
        root.getChildren().clear();
        rectangles.clear();
        for (int i = 0; i<integers.size(); i++) {
            Rectangle rectangle = new Rectangle(i * 20, 500 - integers.get(i), 10, integers.get(i));
            rectangle.setFill(Color.BLACK);
            rectangles.add(rectangle);
        }
        root.getChildren().addAll(rectangles);
    }

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

但是,我只看到最后一次迭代的结果。在此之前,我只能看到应用程序正在运行并且GUI线程被阻止。

如何让后台RxJava计算无阻塞到我的GUI?

编辑:我通过在另一个线程中运行计算代码解决了这个问题,如下所示:

@Override
public void start(Stage primaryStage) throws InterruptedException {

    new Thread(() -> {
        Sorter sorter = new Sorter();
        sorter.getSubject().subscribe(this::drawRectangles);
        try {
            sorter.bubbleSort(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();


    root = new Group();
    Scene scene = new Scene(root, 1500, 500, Color.WHITE);
    primaryStage.show();
    primaryStage.setScene(scene);
}

drawRectangles包装在Platform.runLater(() -> {}表达式中。

这似乎有效,虽然我觉得我可能会以observeOn以某种方式运行它。

1 个答案:

答案 0 :(得分:0)

使用RxJavaFX调度您的UI任务。

您需要在另一个线程而不是UI线程中执行排序任务sorter.bubbleSort。和

observeOn(JavaFxScheduler.getInstance())

将UI任务安排回UI线程。

仅将start方法更改为:

  @Override
  public void start(Stage primaryStage) throws InterruptedException {
    root = new Group();
    Scene scene = new Scene(root, 500, 500, Color.WHITE);
    primaryStage.show();
    primaryStage.setScene(scene);

    Sorter sorter = new Sorter();
    sorter.getSubject()
        .observeOn(JavaFxScheduler.platform())
        .subscribe(this::drawRectangles);
    new Thread(() -> uncheck(() -> sorter.bubbleSort(100))).start();
  }