Search code examples
flutternotificationsriverpod

How to send targeted notifications to a widget with Flutter Riverpod?


My Flutter app has a large number of tiny Stateful Widgets. I want to send a notification to one of them, and induce it to change state. What is the exact mechanism with Riverpod (or any other notification system like Value Change Notifier or Streams) to send a message to a particular widget? I can assign a custom id for each widget, or use a globally unique key to identify them.

If you need some context: My app has a monitoring panel with 100 lamps, resembling physical LEDs, arranged in a 10x10 matrix on the screen. These are custom widgets based on Avatars. Each lamp represents a status (on/off) or an error condition. When a sensor in the physical world raises an alarm, the corresponding widget gets a notification, and the lamp glows red on the UI.

I don't think I should create 100 Riverpod Notifier-Provider objects. But if have a single Notifier, it will invoke the build() method of all the 100 widgets, which is not the goal. I want to tell Riverpod something like this: "Your state has changed. The new value is {'lamp_id' : 42, 'status' : 'on' }. But send this notification only to lamp number 42, and not to the other 99 widgets."

I have no server side infrastructure like Firebase push notifications. Please suggest any client-only solution.


Solution

  • You can make a family class-based provider for this. Add an id parameter to the class-based provider's build method.

    @riverpod
    class LampStatus extends _$LampStatus {
      @override
      bool build(int id) => false;
    
      void turnOn() {
        state = true;
      }
    }
    

    In your lamp widget, watch the provider like this:

    @override
    Widget build(BuildContext context, WidgetRef ref) {
      final status = ref.watch(lampStatusProvider(id));
      
      // ...
    }
    

    This way, each lamp widget will have its own provider, even though you only defined the provider once.

    When you call ref.read(lampStatusProvider(id).notifier).turnOn() somewhere, it will correctly change the status only for the lamp with the given id.