I have this data flow, roughly:
DataGenerator -> DataFormatter -> UI
DataGenerator is something that generates data rapidly; DataFormatter is something that formats it for display purposes; and the UI is just a bunch of Swing elements.
I'd like to make my DataGenerator something like this:
class DataGenerator
{
final private PropertyChangeSupport pcs;
...
public void addPropertyChangeListener(PropertyChangeListener pcl) {
this.pcs.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl) {
this.pcs.removePropertyChangeListener(pcl);
}
}
and just call this.pcs.firePropertyChange(...)
whenever my data generator has new data; then I can just do dataGenerator.addPropertyListener(listener)
where listener
is responsible for pushing the change forward to the DataFormatter and then to the UI.
The problem with this approach, is that there are thousands of dataGenerator changes per second (between 10,000 and 60,000 per second depending on my situation), and the computational cost of formatting it for the UI is high enough that it puts an unnecessary load on my CPU; really all I care about visually is at most 10-20 changes per second.
Is there any way to use a similar approach, but coalesce the change events before they get to the DataFormatter? If I receive multiple update events on a single topic, I just care about displaying the latest one, and can skip all the previous ones.
Two ideas:
PropertyChangeEvent
s. Extend PropertyChangeSupport
, overwrite public void firePropertyChange(PropertyChangeEvent evt)
, fire only if last event was fired more than 50ms (or whatever time seems appropriate) ago. (In fact you should overwrite every fire*
method or at least the one you use in your scenario to prevent the creation of the PropertyChangeEvent
.)I would tend to the second approach.
It sounds like your DataGenerator
doing a lot of non-GUI work on the EDT-thread. I would recommend that your DataGenerator
extend SwingWorker
and by that doing the work in a background thread, implemented in doInBackground
. The SwingWorker could then publish
intermediate results to the GUI, while you have a process
method that receives the last few published chunks on the EDT and update your GUI.
The SwingWorkers process
method does coalesce the published
chunks, so it will not run once for every published intermediate result.
If you only care of the last result on the EDT you can use this code, that only cares about the last chunk in the list:
@Override
protected void process(List<Integer> chunks) {
// get the *last* chunk, skip the others
doSomethingWith( chunks.get(chunks.size() - 1) );
}
Read more on SwingWorker: Tasks that Have Interim Results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With