Skip to main content
V5 - Java Server DocumentationThese docs are for Java Server V5 Only. For all other languages and platforms, continue using SDK v4 until V5 support is available.
You can react to changes in your local store by setting up a store observer. You can read more about store observers in Accessing Data. Store observers are useful when you want to monitor changes from your local Ditto store and react to them immediately. For instance, when your end user updates their profile, asynchronously display changes in realtime.

Understanding Observer Backpressure

When using store observers, callbacks fire every time matching data changes in your local store. In high-frequency scenarios—such as IoT sensors publishing multiple times per second or real-time position tracking—callbacks can fire faster than your application can process them. This leads to a backlog of pending callbacks, excessive memory consumption, and potential crashes. To handle this, Ditto provides registerObserver with DittoChangeListenerWithNextSignal, which gives you explicit control over when the observer can deliver the next update. Instead of automatic callback delivery, you call a signalNext function when your application is ready for the next batch of changes.
Without backpressure control, observer callbacks in high-frequency scenarios can overwhelm your application. Always use registerObserver with DittoChangeListenerWithNextSignal when updates may arrive faster than your app can process them.To determine if you need back pressure control see Choosing the Right Observer Method below.

Setting Up Store Observers

Use registerObserver with DittoChangeListenerWithNextSignal to control when your observer receives updates. The callback includes a signalNext function that you call when ready for the next update.
import com.ditto.java.DittoStoreObserver;
import static com.ditto.java.serialization.DittoCborSerializable.buildDictionary;

DittoStoreObserver observer = ditto.getStore().registerObserverWithSignalNext(
    "SELECT * FROM cars WHERE color = :color",
    buildDictionary().put("color", "blue").build(),
    (result, signalNext) -> {
        try (result) {
            // Process the current result
            updateUI(result.getItems());

            // Signal readiness for next update
            signalNext.signal();
        }
    }
);
For UI updates, consider calling signalNext() after your render cycle completes—for example, inside requestAnimationFrame in JavaScript or after DispatchQueue.main.async completes in Swift.

Basic Store Observer

For low-frequency updates where backpressure is not a concern, use the simpler registerObserver method.
This approach does not provide backpressure control. If updates arrive faster than your callback can process them, callbacks will queue up and may cause memory issues. For high-frequency scenarios, use registerObserver with DittoChangeListenerWithNextSignal instead.
To associate arguments with your query, add them as a parameter.
import com.ditto.java.DittoStoreObserver;
import static com.ditto.java.serialization.DittoCborSerializable.buildDictionary;

DittoStoreObserver observer = ditto.getStore().registerObserver(
    "SELECT * FROM cars WHERE color = :color",
    buildDictionary().put("color", "blue").build(),
    (result) -> {
        // handle change
    }
);

Choosing the Right Observer Method

ScenarioRecommended Method
High-frequency updates (sensors, real-time tracking)registerObserver with DittoChangeListenerWithNextSignal
UI updates that need render-cycle synchronizationregisterObserver with DittoChangeListenerWithNextSignal
Async processing that may take timeregisterObserver with DittoChangeListenerWithNextSignal
Low-frequency updates (user profile changes)registerObserver with DittoChangeListener
Simple use cases with infrequent changesregisterObserver with DittoChangeListener
For more information on memory management with observers, see the Diffing Results section which covers QueryResult lifecycle and proper cleanup patterns.

Canceling a Store Observer

To cancel a store observer, call close() on the observer object. Once canceled, the store observer will stop processing in the background and will no longer call the provided callback.
observer.close();

Accessing Store Observers

To access store observers from the local Ditto store:
ditto.getStore().getObservers();