问题
When I attach listener to observable list and in that listener I try to remove some element, in some cases it passes and in some cases it crashes.
Scenario: Item is removed from a list. It triggers listener, and in that listener I try to delete another item.
- If in listener I try to remove element that is not just next to initially removed, it works OK.
- If in listener I try to remove element that is JUST NEXT to initially removed, it crashes with UnsupportedOperationException!!!
Did anybody had similar problem? Do you have any tips, suggestions or workaround?
I know that you can delete both at the same time, but problem is that in listener I need to detect which items I need to remove also so I delete i there.
Is this a bug in ObservableList?
I would expect that it always work, or at least to always crash.
Here is code example:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ListRemoveFromListener extends Application {
boolean changing = false;
@Override
public void start(Stage primaryStage) throws Exception {
VBox vbox = new VBox();
Button buttonSuccess = new Button("remove success");
buttonSuccess.setOnAction(e -> {
removeSuccess();
});
Button buttonBreak = new Button("Remove breaks");
buttonBreak.setOnAction(e -> {
removeBreaks();
});
vbox.getChildren().addAll(buttonSuccess, buttonBreak);
Scene scene = new Scene(vbox);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* If we try in listener to remove element just next to one that was
* initially removed, exception is thrown.
*/
private void removeBreaks() {
ObservableList<String> list = FXCollections.observableArrayList();
list.add("first");
list.add("second");
list.add("third");
list.add("fourth");
list.add("fifth");
list.add("sixth");
list.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
list.remove("second");
}
});
list.remove("third");
}
/**
* If we try in listener to remove element that is not just next to initially
* removed element, element is removed and all works O.
*/
private void removeSuccess() {
ObservableList<String> list = FXCollections.observableArrayList();
list.add("first");
list.add("second");
list.add("third");
list.add("fourth");
list.add("fifth");
list.add("sixth");
list.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
list.remove("fifth");
}
});
list.remove("third");
}
public static void main(String[] args) {
launch(args);
}
}
回答1:
ListChangeListener.Change documentation states:
the source list cannot be modified inside the listener
You can work around this using a Platform.runLater call to schedule the additional change to be performed at some time in the future:
list.addListener((ListChangeListener<String>) c -> {
if (list.contains("second")) {
Platform.runLater(() -> list.remove("second"));
}
});
be careful when doing so that you don't cause a cascading infinite loop of changes.
来源:https://stackoverflow.com/questions/46214214/javafx-observablelist-remove-element-in-listener-throws-exception