Search code examples
flutterdartdart-asyncdart-stream

Generic Widget for listening Streams in Flutter


I would like to create a StatefulWidget which I'll use all over the app for listening streams of different types. Since I try to keep all the widgets Stateless I wanted to extract this functionality.

I've created this:

class StreamListener<T> extends StatefulWidget {
  const StreamListener({
    Key? key,
    required this.stream,
    required this.onNewData,
    required this.child,
  }) : super(key: key);

  final Stream<T?> stream;
  final void Function(T data) onNewData;
  final Widget child;

  @override
  State<StreamListener> createState() => _StreamListenerState<T>();
}

class _StreamListenerState<T> extends State<StreamListener> {
  late StreamSubscription<T?> streamSubscription;

  @override
  void initState() {
    streamSubscription = (widget.stream as Stream<T?>).listen(
      (T? data) {
        if (data != null) {
          widget.onNewData(data);
        }
      },
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }

  @override
  void dispose() {
    streamSubscription.cancel();
    super.dispose();
  }
}

Then somewhere in the Widgets tree I use:

return StreamListener<int>(
 stream: context.read<MyCubit>().toastStream,
 onNewData: (int data) {
   print("Received: $data");
 },
 child: SomeStatelessWidget(),
}

Stream logic is added to the Cubit like that:

mixin ToastStreamForCubit<T> {
  final StreamController<T> _toastStreamController = StreamController<T>();
  get toastStream => _toastStreamController.stream;

  void emitToastEvent(T event) {
    _toastStreamController.add(event);
  }
}

And when I call let's say emitToastEvent(1).

I receive type '(int) => void' is not a subtype of type '(dynamic) => void'. on line widget.onNewData(data);.

I'm not sure what is going on. I thought I've mapped all the functions and classes to a particular generic type (T), but it still says something about dynamic.


Solution

  • You are missing T while extending State<StreamListener>. It should be

    class _StreamListenerState<T> extends State<StreamListener<T>>