Dart and Flutter Live Query Examples
Use KalamClient.live() for a Flutter list that follows database changes. Each stream value is the complete current row list, with inserts, updates, and deletes already reconciled by the SDK.
Prepare the live-query example
Create app.live_messages using the shared inbox schema. Install kalam_link, initialize it once, and obtain an authenticated client using Dart setup. Production apps should use their signed-in user’s auth provider.
The widget below accepts that connected client. Mount LiveInbox(client: client) after connection succeeds, and show connection errors in your app’s sign-in/connection screen. The widget owns its subscription; your session service owns and disposes the client.
Drop in a Flutter inbox
Place the widget in a bounded area such as Scaffold.body or Expanded. StreamBuilder cancels its subscription when removed and when its stream is replaced. Do not construct client.live() inside build(): an unrelated rebuild would otherwise create another stream.
The error branch comes before the empty branch, so a rejected query cannot look like an empty inbox. live() converts server subscription errors into stream errors. In contrast, low-level liveEvents() exposes SubscriptionError as an event; handle it in your event switch as well as handling stream failures.
Verify the screen
Run the insert, update, and delete statements from another connection with the same user. Expect the new body, then the edited body, then removal without duplicates. This USER table is private to that identity.
Temporarily use a nonexistent table to verify the error screen. Fix the name and restart the example. For a permissions or connection problem that has been corrected without changing code, use Retry. Navigate away and confirm the subscription disappears from client.getSubscriptions() after cancellation has completed.
ConnectionState.active describes the Dart stream, not socket health. A reconnecting stream can remain active with cached rows. Use your application’s connection state for an offline banner, and verify recovery with a normal SELECT before considering previously displayed rows current.
Use the stream without Flutter
In a service, keep the StreamSubscription and cancel it explicitly:
Retry and persistence rules
- Keep the primary key in the SELECT.
mapRowconverts cell wrappers into app models;keyColumnsdefines row identity for reconciliation. - Raw subscription SQL is
SELECT ... FROM ... WHERE ..., withoutORDER BYorLIMIT. Sort a copy for display.batchSize,lastRows, and the direct materializer’slimithave different purposes. - Let the SDK manage transient transport reconnects. Explicit Retry replaces this widget’s stream; do not add a timer that continually opens subscriptions.
- Correct authentication, authorization, or SQL failures before retrying. For writes, check both thrown exceptions and
QueryResponse.success; see Dart querying. - These rows live in memory. Do not persist only a checkpoint and resume into an empty list after app restart. Use Kalam Sync for a durable local cache, and Offline Actions for queued writes.
- A gap or expired cursor requires recovery within the bounded replay contract. A live stream is not an unlimited event archive.