Stream Controller

A Stream Controller is a special variable type used to push and listen to data over time. It enables reactive programming patterns where widgets automatically update in response to data changes, making it perfect for real-time updates, notifications, or any scenario where data arrives asynchronously.

Supported Widgets

The Stream Controller can be used with:

When to Use

Use a Stream Controller when you need to:

  • Handle real-time data updates (chat messages, notifications)

  • Emit values over time from actions or events

  • Create reactive UI that responds to data streams

  • Implement event-driven architectures

  • Push multiple values to the same widget over time

  • Broadcast data to multiple listeners

Creating a Stream Controller

  1. Navigate to Variables in your project

  2. Click Add Variable

  3. Select Stream Controller as the type

  4. Give it a descriptive name (e.g., messageStream, notificationStream)

Binding to Widgets

Stream Builder Example

Stream Builder:
  Stream: ${messageStream}
  
  Builder:
    Text: ${streamData.message}
    Text: ${concat("Received at: ", streamData.timestamp)}

The Stream Builder widget will automatically rebuild whenever new data is emitted to the stream.

Controller Methods

Use the Control Object action to invoke these methods on the controller.

add

Emits a value to the stream, triggering all listeners to update.

Parameter
Type
Description

value

Any

Any JSON-compatible value to emit

Example Use Cases:

  • Emit new message: value: {"message": "Hello", "timestamp": "10:30 AM"}

  • Emit notification: value: {"type": "info", "text": "Update available"}

  • Emit simple value: value: 42

  • Emit string: value: "Status changed"

When to Use:

  • When new data arrives from an API or event

  • Responding to user actions

  • Broadcasting updates to UI


close

Closes the stream, preventing further emissions.

No parameters required.

When to Use:

  • Cleanup when leaving a page

  • Stopping real-time updates

  • Resource management


Common Use Cases

1. Real-Time Chat Messages

Display incoming chat messages as they arrive.

Setup:

Variable: chatStream (Stream Controller)

Stream Builder:
  Stream: ${chatStream}
  
  Builder:
    Container (Message Bubble):
      Text: ${streamData.sender}
      Text: ${streamData.message}
      Text: ${streamData.timestamp}

Implementation:

On WebSocket Message Received:
  Control Object:
    Object: ${chatStream}
    Method: add
    Arguments:
      value: {
        "sender": ${message.sender},
        "message": ${message.text},
        "timestamp": ${message.time}
      }

2. Live Notifications

Show real-time notifications to users.

Setup:

Variable: notificationStream (Stream Controller)

Stream Builder:
  Stream: ${notificationStream}
  
  Builder:
    Container (Notification Banner):
      Background: ${if(isEqual(streamData.type, 'error'), 'red', 'blue')}
      Text: ${streamData.title}
      Text: ${streamData.message}

Implementation:

On API Response:
  Control Object:
    Object: ${notificationStream}
    Method: add
    Arguments:
      value: {
        "type": "success",
        "title": "Success!",
        "message": "Data saved successfully"
      }

3. Progress Updates

Stream progress updates for long-running tasks.

Setup:

Variable: progressStream (Stream Controller)

Stream Builder:
  Stream: ${progressStream}
  
  Builder:
    Linear Progress Bar:
      Value: ${streamData.percent}
    Text: ${streamData.status}

Implementation:

On Upload Progress:
  Control Object:
    Object: ${progressStream}
    Method: add
    Arguments:
      value: {
        "percent": ${uploadPercent},
        "status": ${concat("Uploading: ", uploadPercent, "%")}
      }

4. Live Search Results

Stream search results as user types.

Setup:

Variable: searchResultsStream (Stream Controller)

Text Form Field:
  On Change:
    API Call: searchAPI
      On Success:
        Control Object:
          Object: ${searchResultsStream}
          Method: add
          Arguments:
            value: ${apiResponse.data.results}

Stream Builder:
  Stream: ${searchResultsStream}
  
  Builder:
    ListView:
      Data Source: ${streamData}

5. Event Broadcasting

Emit events from one part of the app and listen elsewhere.

Setup:

Variable: appEventStream (Stream Controller)

// Emit event
On Button Click:
  Control Object:
    Object: ${appEventStream}
    Method: add
    Arguments:
      value: {
        "event": "user_logged_in",
        "userId": ${currentUser.id}
      }

// Listen to events
Stream Builder:
  Stream: ${appEventStream}
  
  Builder:
    Conditional Builder:
      Condition: ${isEqual(streamData.event, 'user_logged_in')}
      True:
        Text: ${concat("Welcome, User ", streamData.userId)}

6. Cleanup on Page Exit

Close stream when leaving a page to prevent memory leaks.

On Page Dispose:
  Control Object:
    Object: ${messageStream}
    Method: close

Best Practices

  • One stream per data type: Create separate streams for different types of data (messages, notifications, etc.)

  • Use descriptive names: Name streams after their purpose (chatStream, notificationStream)

  • Close streams when done: Always close streams when they're no longer needed to free resources

  • Emit structured data: Use JSON objects with consistent structure for easier handling

  • Handle initial state: Stream Builder should handle the case where no data has been emitted yet

  • Don't emit too frequently: Avoid emitting hundreds of times per second; consider throttling or debouncing

  • Validate data before emitting: Ensure data is valid and in the expected format before calling add

Common Patterns

Emit Simple Value

Control Object:
  Object: ${stream}
  Method: add
  Arguments:
    value: "Hello World"

Emit Complex Object

Control Object:
  Object: ${stream}
  Method: add
  Arguments:
    value: {
      "id": 123,
      "title": "New Item",
      "timestamp": ${currentTimestamp}
    }

Close Stream on Exit

On Page Dispose:
  Control Object:
    Object: ${stream}
    Method: close

Conditional Emission

If ${shouldNotify}:
  Control Object:
    Object: ${notificationStream}
    Method: add
    Arguments:
      value: ${notificationData}

Stream from API Response

On API Success:
  Control Object:
    Object: ${dataStream}
    Method: add
    Arguments:
      value: ${apiResponse.data}

Stream Builder Integration

The Stream Builder widget is designed to work with Stream Controllers:

Stream Builder:
  Stream: ${streamController}
  
  Builder:
    // Access emitted data via ${streamData}
    Text: ${streamData.property}

Whenever you call add() on the Stream Controller, the Stream Builder automatically rebuilds with the new streamData.

Troubleshooting

Stream Not Updating

  • Ensure the Stream Controller is properly bound to Stream Builder using ${streamName}

  • Check that add is being called with valid data

  • Verify the stream hasn't been closed

Stream Builder Not Rebuilding

  • Confirm the stream property is set correctly in Stream Builder

  • Check that data is being emitted (use console/debug to verify)

  • Ensure the value being emitted is JSON-compatible

Memory Leaks

  • Always close streams when leaving pages

  • Don't create new Stream Controllers repeatedly without closing old ones

  • Use close() in page disposal lifecycle

Last updated