I am trying to develop an JavaFX application to simulate some elevator system.
Each object Elevator is running on its own thread and I want to display each Elevator.toString() in a listview. The problem is that after running the application for a while I will get NullPointerException or IndexOutOfBounds from one, or more, of the elevator threads. I have created a ObservableList of Elevators where I listen for any property changes, then I have another ObservableList of type string that is connected to the listView. The second one is update every time the change listener fires a wasUpdated() from the first list.
final ObservableList<String> elevators = FXCollections.observableArrayList();
final ObservableList<Elevator> obsList = FXCollections.observableArrayList(
new Callback<Elevator, Observable[]>() {
@Override
public Observable[] call(Elevator param) {
return new Observable[]{
param.getCurrentFloorProp(),
param.getDirProp(),
param.getSmallSchedule(),
param.getDoorsProp(),
param.getStatusProp()
};
}
}
);
obsList.addListener(new ListChangeListener<Elevator>() {
@Override
public void onChanged(Change<? extends Elevator> c) {
c.reset();
while (c.next()) {
if (c.wasUpdated()) {
Platform.runLater(() -> {
elevators.set(c.getFrom(), obsList.get(c.getFrom()).toString());
});
}
}
}
});
When trying to fix it I have two thoughts, either the ChangeListener fires more changes then the Platform.runLater has time to process or something in the same line as https://stackoverflow.com/a/31414801/9696324. However I cannot get the proposed solutions to work, it usually occurs after 2-3 minutes of running the program without any problems.
When the first error occur the GUI usually freeze (while the program is still running good) and then starts spamming the same errors.
Any thoughts or pointers would be very appreciated, thank you.
The properties are declared in the elevator constructor:
currentFloor = new SimpleIntegerProperty(INITIAL_FLOOR);
smallSchedule = new SimpleStringProperty("");
status = new SimpleBooleanProperty(true);
dir = new SimpleStringProperty("S");
doors = new SimpleStringProperty("Doors closed");
And the following getters and setter:
public StringProperty getSmallSchedule() {
return smallSchedule;
}
public StringProperty getDoorsProp() {
return doors;
}
public StringProperty getDirProp() {
return dir;
}
public IntegerProperty getCurrentFloorProp() {
return currentFloor;
}
public BooleanProperty getStatusProp() {
return status;
}
public void setCurrentFloor(int floorNr) {
currentFloor.set(floorNr);
}
public void setStatus(boolean status) {
this.status.set(status);
}
public void setDir(char dir) {
this.dir.set(Character.toString(dir));
}
public void setSmallSchedule() {
String temp = "";
for(int i = 0; i < travelSchedule.size()-1;i++) {
if(travelSchedule.get(i)==INT_MAX || i > 2)
break;
temp += " " + travelSchedule.get(i);
}
smallSchedule.set(temp);
}
public void doors(){
try {
Thread.sleep(doorOpen);
doors.set("Doors open");
Thread.sleep(doorWait);
checkMBox();
Thread.sleep(doorClose);
doors.set("Doors closed");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}