Flutter with Riverpod and Websocket . Get the error: flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception:

739 Views Asked by At

I am trying to learn Riverpod.

This code uses , flutter_riverpod, and web_socket_channel. The app connects to a WebSocket server to a IP address and on port 81, and uses the Riverpod library to manage the state of the app. The app has several StateProviders, which are used to manage the state of the app, such as the connection status, the switch status, and the number of cycles and forces sensor. The app also has a StreamProvider which listens for messages from the WebSocket server and updates the state of the app accordingly. The UI of the app displays the connection status, the switch status, the number of cycles and force sensor, and a switch to turn on/off the power. The app also handles the sending of messages to the WebSocket server when the switch is turned on or off.

When i debugg, restart or when i get data over the WebSocket i get a error message for a short time and the code continuous working after normal.

The error is from Riverpod: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Tried to modify a provider while the widget tree was building. If you are encountering this error, chances are you tried to modify a provider in a widget life-cycle, such as but not limited to:

I cannot see in the code what can be the cause of this.

Like i said i am trying to learn Riverpod and also at this point i am not sure if i am using correctly.

Thanks in advance for some help.

Follows the code:

// ignore_for_file: avoid_print

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:convert';
import 'package:web_socket_channel/io.dart';
import 'package:blinking_text/blinking_text.dart';

final switchedProvider = StateProvider<bool>((ref) => false);
final connectedStatusProvider = StateProvider<bool>((ref) => false);
final cycleStatusProvider = StateProvider<int>((ref) => 0);
final forceStatusProvider = StateProvider<int>((ref) => 0);

final webSocketProvider = StateProvider<IOWebSocketChannel>((ref) {
  final channel = IOWebSocketChannel.connect(Uri.parse('ws://192.168.206.115:81'));
  ref.onDispose(() => channel.sink.close());
  return channel;
});

void sendDataOn(IOWebSocketChannel channel) {
  channel.sink.add("poweron");
}

void sendDataOff(IOWebSocketChannel channel) {
  channel.sink.add("poweroff");
}

void updateStateFromMessage(String message, WidgetRef ref) {
  print(message);
  Map<String, dynamic> jsondat = json.decode(message);
  String data = json.encode(jsondat);
  if (data.contains("connected")) {
    ref.read(connectedStatusProvider.notifier).state = true;
    ref.read(cycleStatusProvider.notifier).state = jsondat['cycle'];
    ref.read(forceStatusProvider.notifier).state = jsondat['force'];
  }
}

final providerOfMessages = StreamProvider.autoDispose<String>(
  (ref) async* {
    final channel = ref.watch(webSocketProvider);
    // Close the connection when the stream is destroyed
    ref.onDispose(() => channel.sink.close());

    await for (final value in channel.stream) {
      yield value.toString();
    }
  },
);

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        brightness: Brightness.light,
      ),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
      ),
      themeMode: ThemeMode.dark,
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends ConsumerWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    var connected = ref.watch(connectedStatusProvider);
    final channel = ref.watch(webSocketProvider);
    var switched = ref.watch(switchedProvider);
    final messages = ref.watch(providerOfMessages);
    var istcycles = ref.watch(cycleStatusProvider);
    var istforcesensor = ref.watch(forceStatusProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('WebSocket & Riverpod'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              const Text(
                'ESP32',
              ),
              Container(
                child: connected
                    ? Text(
                        "CONNECTED",
                        style: TextStyle(
                          fontSize: 25.0,
                          letterSpacing: 2.0,
                          color: Colors.green[400],
                        ),
                      )
                    : const BlinkText(
                        "DISCONNECTED",
                        duration: Duration(milliseconds: 250),
                        beginColor: Colors.red,
                        endColor: Colors.white,
                        style: TextStyle(
                          fontSize: 25.0,
                          letterSpacing: 2.0,
                          color: Colors.red,
                        ),
                      ),
              ),
              Text(
                'Cycles: ${istcycles.toString()}',
                style: const TextStyle(fontSize: 30),
              ),
              Text(
                'Force: ${istforcesensor.toString()}',
                style: const TextStyle(fontSize: 30),
              ),
              Switch(
                value: switched,
                activeColor: connected && switched ? Colors.green[400] : Colors.red,
                inactiveThumbColor: connected && switched ? Colors.grey.shade400 : Colors.red,
                inactiveTrackColor: connected && switched ? Colors.grey.shade600 : Colors.red[200],
                onChanged: (bool value) {
                  ref.read(switchedProvider.notifier).state = value;
                  if (value == false) {
                    sendDataOff(channel);
                  } else {
                    sendDataOn(channel);
                  }
                },
              ),
              messages.when(
                data: (message) {
                  updateStateFromMessage(message, ref);
                  return const Text('');
                },
                loading: () => const CircularProgressIndicator(),
                error: (_, __) => const Text('Probably server not running, run "yarn start" under the server folder!'),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Follows the complete code:

1

There are 1 best solutions below

0
Carlos Costa On

I found a solution.

Moving the updateStateFromMessage function to be called after the build, by using the Future.delayed function. It will delay the execution of the function until after the build is complete.