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

ListCell: must not use ChangeListener to itemsProperty

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 9
    • None
    • javafx
    • 9-ea-107

      It's a left-over from some old (fixed) issues: if we need to listen to changes in list-valued properties, we need to register an InvalidationListener (_not_ a ChangeListener) to reliably get notified on changes to the property: the property doesn't fire to ChangeListeners on replacing the value with an equal but not-same list.

      ListCell still uses a ChangeListener to the itemsProperty, so it's listening to the wrong list on replacing that list with an equal but not same list. Simply look at the code ;-)

      Anyway, example below demonstrates the issue, run and:

      - click replace-items
      - click on update-previous
      - expected: no call to updateItem
      - actual: call to updateItem

      on the bright side, changing the current items updates the cell as expected:

      - click on update-current
      - expected and actual: updateItem called and visuals updated

      This might indicate that the items listener on the cell isn't needed at all (seems to be a singularity in the cell zoo, anyway) - any update now seems to be triggered reliably by listSkin.

      public class ListCellListeningToOldItems extends Application {

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

          int idCount;
          @Override
          public void start(Stage stage) {
              ObservableList<String> items = createItems(null);
              ListView<String> listView = new ListView<>(items);
             
              listView.setCellFactory(lv -> {
                  System.out.println("created");
                  ListCell<String> cell = new ListCell<String>() {
                      @Override
                      protected void updateItem(String item, boolean empty) {
                          super.updateItem(item, empty);
                          setText(item);
                          if (!empty) {
                              System.out.println("item updated to '" + item + "'" + "for " + getId());
      // new RuntimeException("who's calling? \n").printStackTrace();
                          }
                      }
                  };
                  cell.setId("cell-id: " + idCount++);
                  return cell;
               });

              Button reset = new Button("Replace items to equal list");
              reset.setOnAction(e -> {
                  previous = listView.getItems();
                  listView.setItems(createItems(listView));
              });
              
              Button updateOld = new Button("update previous list at 0");
              updateOld.setOnAction(e -> {
                  if (previous == null || previous == listView.getItems()) {
                      System.out.println("same items");
                      return;
                  }
                  previous.set(0, "changed old");
              });
              Button updateCurrent = new Button("Update current list at 0");
              updateCurrent.setOnAction(e -> {
                  Object old = listView.getItems().get(0);
                  listView.getItems().set(0, old + "X");
                  
              });
              Parent content = new VBox(listView, reset, updateOld, updateCurrent);
              stage.setScene(new Scene(content, 200, 180));
              stage.setTitle(System.getProperty("java.version"));
              stage.show();

          }

          int count;
          private ObservableList<String> previous;
          /**
           * Creates and returns a list the is equal to but not the same as
           * the current items of the list.
           */
          protected ObservableList<String> createItems(ListView lv) {
              ObservableList<String> items = lv != null ? FXCollections.observableArrayList(lv.getItems())
                      : FXCollections.observableArrayList("Foo");
              return items;
          }
      }

            jgiles Jonathan Giles
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: