lundi 3 novembre 2014

Updating the color of rows of a TableView consumes too much CPU


Vote count:

0




I am making an application that receives alerts.


An alert can have 4 possible states: Unresolved_New_0 Unresolved_New_1 Unresolved_Old Resolved


When an alert is received, it is in Unresolved_New_0 state. For 10 seconds, every 0.5s the state changes from Unresolved_New_0 to Unresolved_New_1 and vice-versa. Depending on state I, set a different background color to the table row (so that it flashes, for 10s). When the 10s pass, the alert transitions to Unresolved_Old state. This causes its color to stop changing.


To implement this, I a ScheduledThreadPoolExecutor that I use to submit an implementation of Runnable that for some time executes a runnable using Platform.runLater.



static class FxTask extends Runnable {

/**
*
* @param runnableDuring Runnable to be run while the task is active (run on the JavaFX application thread).
* @param runnableAfter Runnable to be run after the given duration is elapsed (run on the JavaFX application thread).
* @param duration Duration to run this task for.
* @param unit Time unit.
*/
public static FxTask create(final Runnable runnableDuring, final Runnable runnableAfter, final long duration, final TimeUnit unit) {

return new FxTask(runnableDuring, runnableAfter, duration, unit);
}

@Override
public void run() {

if (System.nanoTime() - mTimeStarted >= mTimeUnit.toNanos(mDuration) )
{
cancel();
Platform.runLater(mRunnableAfter);
}
else
Platform.runLater(mRunnableDuring);
}

private FxTask(final Runnable during, final Runnable after, final long duration, final TimeUnit unit) {

mRunnableDuring = during;
mRunnableAfter = after;

mDuration = duration;
mTimeUnit = unit;

mTimeStarted = System.nanoTime();
}

private final Runnable mRunnableDuring;
private final Runnable mRunnableAfter;
private final long mDuration;
private final TimeUnit mTimeUnit;

private final long mTimeStarted;
}


And I schedule Alerts using that Runnable as follows:



final Alert alert = new Alert(...);

scheduler.scheduleAtFixedRate(FxTask.create(
() -> {
switch (alert.alertStateProperty().get()) {

case UNRESOLVED_NEW_0:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_1);
refreshTable(mAlertsTable);
break;

case UNRESOLVED_NEW_1:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_0);
refreshTable(mAlertsTable);
break;
}
},
() -> { // This is run at the end
if (equalsAny(alert.alertStateProperty().get(), Alert.State.UNRESOLVED_NEW_0, SpreadAlert.State.UNRESOLVED_NEW_1)) {
alert.alertStateProperty().set(Alert.State.UNRESOLVED_OLD);
refreshTable(mAlertsTable);
}
},
10, TimeUnit.SECONDS), 0, 500, TimeUnit.MILLISECONDS
);


Note: alertStateProperty() is not shown on the TableView (it is not bound to any of its columns). So in order to force JavaFx to redraw, I have to use refreshTable(), which unfortunately redraws the whole table (?).



public static <T> void refreshTable(final TableView<T> table) {

table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
}


The problem is that if I create a small number of Alerts at the same time, CPU usage goes very high: from 20% to 84% sometimes, averaging at about 40%. When the 10s pass for all alerts, CPU consumptions returns to 0%. If I comment out refreshTable(), CPU stays near 0%, which indicates that it is the problem.


Why is so much CPU being used? (I have 8 cores by the way). Is there another way to redraw just a single row without redrawing the whole table?


I even tried a 'hacky' method -- changing all values of the Alerts and then resetting them back to cause JavaFx to detect the change and redraw, but CPU was again at the same levels.



asked 30 secs ago







Updating the color of rows of a TableView consumes too much CPU

Aucun commentaire:

Enregistrer un commentaire