How to add a listener to a GenericEntry from ShuffleBoard?

I want to be able to edit values in the Shuffleboard and have those values reflected in the running code. I can do this by getting a GenericEntry from the Shuffleboard like this.

ShuffleboardTab tab = Shuffleboard.getTab("My Tab");
GenericEntry entry = tab.add("Max Speed", 1.0).getEntry();

From here, I can poll the GenericEntry for any value changes and run code if any changes were detected.

NetworkTableValue[] newValues = entry.readQueue();
if (newValues.length != 0) {
    doThingsWithUpdatedValue(newValues[0])
}

I would like to change this polling code to use a listener instead, but I am not familiar with how to do this. What would the code look like to listen for changes to the GenericEntry and run my doThingsWithUpdatedValue when a change is detected?

Here’s how to do it with listeners, but I want to caution you that using a listener means that the listener callback will be called on a separate thread, so you’ll need to be responsible for providing mutex protection of any state shared with the main robot loop. Here be dragons if you’re not already familiar with multithreaded programming. (In future years we may change this so listeners on the default instance run synchronously with the main robot loop, but right now it’s a separate thread.)

See also Listening for Changes — FIRST Robotics Competition documentation (wpilib.org)

NetworkTableInstance.getDefault().addListener(
  entry,
  EnumSet.of(NetworkTableEvent.Kind.kValueAll, NetworkTableEvent.Kind.kImmediate),
  event -> {
    doThingsWithUpdatedValue(event.valueData.value);
  });