skip to Main Content

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 10×10 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.

2

Answers


  1. Chosen as BEST ANSWER

    I followed the very useful hint of @Dhafin Rayhan and solved the problem of client-specific notifications using Rivarpod.

    Documentation on this is virtually non-existent or not easy to find. So I am placing the missing pieces for anyone's reference.

    First you create a FamilyNotifier with any template. Pass a parameter to the build() function that will uniquely identify a particular listener target.

    //Family Notifier and provider in Riverpod:
    
    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    
    final myUserProvider = NotifierProviderFamily<UserNotifier, String, int>(UserNotifier.new);
    
    class UserNotifier extends FamilyNotifier<String, int> {
      UserNotifier();
    
      @override
      String build(int userid) {
        return 'Guest'; // initial value
      }
    
      void setUser(String newValue) {
        state = newValue;
      }
    }
    

    Then create a top level NotifierProviderFamily object that clients can subscribe to. Only the listener with the correct id will receive the notification.

    //Event sender - ConsumerStatefulWidget:
    ref.read(myUserProvider(123).notifier).setUser('Noah');
    ref.read(myUserProvider(456).notifier).setUser('Moses');
    
    //Event receiver - ConsumerWidget1:
    String name = ref.watch(myUserProvider(123));
    
    // Event receiver - ConsumerWidget2:
    String name = ref.watch(myUserProvider(456));
    

  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search