Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8096365

ObservableList throws "java.lang.IllegalStateException: Not on FX application thread" if item is added at position 0 in ObservableList

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P1 P1
    • None
    • 8u20
    • javafx
    • Windows 7 x64. All current latest patches.

      *** EXACT ISSUE VERSION ***
      JDK 8, 8u20 b19

      *** IMPORTANT ***
      This worked on 8u05, must've appeared in 8u20 b19, possibly between b10+ and b19 as I don't recall seeing it before and I've stayed up to date on betas.

      *** ISSUE ***
      If you have a table updated from an observable list that keeps getting items appended to it from a background task/service, this works as expected and the table updates. BUT if you start adding those items at position 0 in the observable list, you get immediate exceptions saying:

       java.lang.IllegalStateException: Not on FX application thread

      *** CODE TO REPRODUCE ***
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.concurrent.Task;
      import javafx.scene.Scene;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.control.cell.PropertyValueFactory;
      import javafx.scene.layout.BorderPane;
      import javafx.stage.Stage;

      /**
       * Problem class showing that updating an observable list at position 0 causes IllegalStateExceptions
       */
      public class ObservableListProblem extends Application {

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

      final BorderPane wrapper = new BorderPane();

      TableView<OneRow> table = new TableView<OneRow>();
      table.getSelectionModel().setCellSelectionEnabled(false);
      table.setEditable(false);

      final ObservableList<OneRow> tableData = FXCollections.observableArrayList();
      TableColumn<OneRow, String> col1 = new TableColumn<OneRow, String>("First Name");
      col1.setCellValueFactory(new PropertyValueFactory<OneRow, String>("firstName"));
      TableColumn<OneRow, String> col2 = new TableColumn<OneRow, String>("Last Name");
      col2.setCellValueFactory(new PropertyValueFactory<OneRow, String>("lastName"));

      table.setItems(tableData);
      table.getColumns().add(col1);
      table.getColumns().add(col2);

      wrapper.setCenter(table);

      Scene mainScene = new Scene(wrapper, 800, 600);
      stage.setScene(mainScene);

      Task<Void> updateTask = new Task<Void>() {
      @Override
      protected Void call() throws Exception {
      while (true) {
      // CODE THAT WORKS
      //tableData.add(new OneRow("xxx", "yyyy"));
      // CODE THAT MAKES IT BLOW UP
      tableData.add(0, new OneRow("xxx", "yyyy"));

      Thread.sleep(1000);
      }
      }

      };
      new Thread(updateTask).start();

      stage.show();

      stage.setOnCloseRequest(e -> {
      Platform.exit();
      System.exit(0);
      });

      }

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

      public class OneRow {

      public OneRow(String firstName, String lastName) {
      setFirstName(firstName);
      setLastName(lastName);
      }

      private StringProperty _firstNameProperty;

      private StringProperty _lastNameProperty;

      public StringProperty firstNameProperty() {
      if (_firstNameProperty == null) {
      _firstNameProperty = new SimpleStringProperty();
      }

      return _firstNameProperty;
      }

      public void setFirstName(String firstName) {
      firstNameProperty().set(firstName);
      }

      public String getFirstName() {
      return firstNameProperty().get();
      }

      public StringProperty lastNameProperty() {
      if (_lastNameProperty == null) {
      _lastNameProperty = new SimpleStringProperty();
      }

      return _lastNameProperty;
      }

      public void setLastName(String lastName) {
      lastNameProperty().set(lastName);
      }

      public String getLastName() {
      return lastNameProperty().get();
      }

      }
      }

      *** FULL EXCEPTION ***

      Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
      at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
      at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
      at javafx.scene.Scene.addToDirtyList(Scene.java:485)
      at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
      at javafx.scene.Node.impl_markDirty(Node.java:415)
      at javafx.scene.Node.notifyParentsOfInvalidatedCSS(Node.java:8709)
      at javafx.scene.Node.requestCssStateTransition(Node.java:8639)
      at javafx.scene.Node.pseudoClassStateChanged(Node.java:8680)
      at javafx.scene.control.Cell$3.invalidated(Cell.java:456)
      at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
      at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
      at javafx.scene.control.Cell.setSelected(Cell.java:476)
      at javafx.scene.control.Cell.updateSelected(Cell.java:684)
      at javafx.scene.control.TableRow.updateSelection(TableRow.java:291)
      at javafx.scene.control.TableRow.lambda$new$57(TableRow.java:101)
      at javafx.scene.control.TableRow$$Lambda$193/377640639.onChanged(Unknown Source)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TableView.java:2880)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.lambda$new$47(TableView.java:1984)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel$$Lambda$79/1484689336.onChanged(Unknown Source)
      at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
      at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
      at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
      at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
      at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
      at javafx.collections.transformation.TransformationList.lambda$getListener$16(TransformationList.java:106)
      at javafx.collections.transformation.TransformationList$$Lambda$81/1149516160.onChanged(Unknown Source)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
      at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
      at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
      at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
      at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
      at com.sun.javafx.scene.control.SelectedCellsMap.clear(SelectedCellsMap.java:183)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2561)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.updateSelection(TableView.java:2185)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.access$2300(TableView.java:1959)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:2057)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
      at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
      at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
      at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
      at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
      at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:50)
      at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:1)
      at javafx.concurrent.Task$TaskCallable.call(Task.java:1409)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.lang.Thread.run(Thread.java:745)

            msladecek Martin Sládeček
            ecrumhornjfx Emil Crumhorn (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: