Flutter : trigger a change of screen on a websocket message

1,453

You can use a stream for that. You can register the websocket response, and when it returns you can add it to the stream, and then on your screen you use a StreamBuilder to subscribe to the stream and navigate when needed. Something like this:

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

// Create a stream to receive the values
var webSocketStream = new BehaviorSubject<String>();

onMessageReceived(data) {
  print("new message: " + data + " !");
  data = jsonDecode(data);
  data.forEach((key, value) {
    switch (key) {
      case "state":
        // Write to the stream
        webSocketStream.add(value);
        break;
    }
  });
}

class CheckWebSocket extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder<String>(
          // Subscribe to the stream
          stream: webSocketStream,
          builder: (context, snapshot) {
            // When the stream changes navigate
            if (snapshot.hasData && snapshot.data == "start") {
              Navigator.pushNamed(context, "/path");
            } else {
              return Container();
            }
          }),
    );
  }
}

I used rxdart for that, because it makes dealing with streams simpler. I also recommend that you extract the code that reads the websocket to a separate class, I put everything in one file just to make it simpler to understand.

Share:
1,453
Maël Gassmann
Author by

Maël Gassmann

Updated on December 09, 2022

Comments

  • Maël Gassmann
    Maël Gassmann over 1 year


    I'm currently working on a flutter app with a websocket. I want to change the current screen with a Navigator.pushNamed(context, '/path') in the method that is triggered by the websocket on a new message. The problem is that I don't have any context in this method.

    So how to change the current screen from this method ?
    I dont know if I'm thinking in the wrong way or if I just don't understand something.

    Here is the method that is triggered on a new websocket message, his class is not a widget. This object is contained in every screen I create but his variable _parent is always set to match the active screen.

       onMessageReceived(data) {
            print("new message: " + data + " !");
            data = jsonDecode(data);
            data.forEach((key, value) {
              switch (key) {
                case "state":
                  _parent.newState(value);
                  break;
              }
          });
      }
    

    Here is the method of the widget:

      newState(state){
        if(state == "start"){
          Navigator.pushNamed(, "/path");
        }
      }
    

    Thanks in advance

    • Mazin Ibrahim
      Mazin Ibrahim about 5 years
      is it necessary for you to navigate to other screen or you just want to show the data of the websocket ?
    • Maël Gassmann
      Maël Gassmann about 5 years
      @MazinIbrahim I really want to navigate to an another screen.
    • user3875913
      user3875913 almost 4 years
      @MaëlGassmann for this i think you need to call setState instead of new state to get the rerender
  • Maël Gassmann
    Maël Gassmann about 5 years
    Thanks for your answer, When I implemented that in my app, I got an error because it couldn't finish to build before navigating : The following assertion was thrown building StreamBuilder<String>(dirty, state: I/flutter (32357): _StreamBuilderBaseState<String, AsyncSnapshot<String>>#489bf): I/flutter (32357): setState() or markNeedsBuild() called during build.
  • Ricardo Smania
    Ricardo Smania about 5 years
    I forgot to return an empty container if the snapshot has no data, please try again.
  • Maël Gassmann
    Maël Gassmann about 5 years
    Still, the same error is showing. Are you sure that you can navigate during build ?
  • Maël Gassmann
    Maël Gassmann about 5 years
    Anyway, I found a solution : If snapshot has no data I just show a different scaffold than if he has data. Thanks a lot.