Flutter - динамическое создание виджета из сообщения websocket - Необработанное исключение: setState () вызывается в конструкторе

Я хочу динамически добавлять ListTile, когда получаю данные из веб-сокета. ListView кажется не готовым, когда я добавляю новые данные в свой глобальный список.

Я получаю эту ошибку

[ОШИБКА: flutter / shell / common / shell.cc (242)] Необработанное исключение Dart: setState () вызывается в конструкторе: _MyHomePageState # 4c6c6 (состояние жизненного цикла: создано, нет виджета, не смонтировано)

Ошибка произошла при обработке этого кода

  void addItem(Item item) {
    setState(() {
      items.add(item);
    });
  }

Я пытался применить эти решения, но у меня ничего не работает:

Вот мое тестовое приложение:

зависимости

dependencies:
  flutter:
    sdk: flutter
  web_socket_channel: ^2.0.0
  intl: ^0.17.0

main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:test_add_from_websocket/Item.dart';
import 'package:test_add_from_websocket/websocket.dart';

void main() {
  runApp(MyApp());
}

Future _init() async {
  final WebSocket _socket = WebSocket();
  _socket.connect('wss://echo.websocket.org', connectionListener, messageListener);
}

void connectionListener(WebSocket socket, bool connected) {
  print('Status : ' + (connected ? 'Connected' : 'Failed to connect'));
}

void messageListener(WebSocket socket, String message) {
  print('websocket received: $message');
  Map itemMap = jsonDecode(message);
  var _item = Item.fromJson(itemMap);
  MyHomePage().addItem(_item);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FutureBuilder(
        future: _init(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            return MyHomePage();
          } else {
            return Text('Loading');
          }
        },
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();

  void addItem(Item item) {
    _MyHomePageState().addItem(item);
  }
}

class _MyHomePageState extends State<MyHomePage> {
  void addItem(Item item) {
    setState(() {
      items.add(item);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add from websocket event'),
      ),
      body: ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            return ListTile(
              leading: Icon(Icons.access_time),
              title: Text(items[index].time),
            );
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          DateTime now = DateTime.now();
          Item _item = Item(
            time: DateFormat.Hm().format(now),
          );
          print(_item.time);
          final WebSocket _socket = WebSocket();
          _socket.send(jsonEncode(_item));
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Мой класс WebSocket

import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:web_socket_channel/status.dart' as status;

class WebSocket {
  static final WebSocket _instance = WebSocket._internal();

  factory WebSocket() => _instance;

  WebSocket._internal();

  String _url;
  bool _connected;
  WebSocketChannel _channel;

  connect(String url, Function connectionListener, Function messageListener) {
    try {
      _url = url;
      _channel = IOWebSocketChannel.connect(_url);
      _connected = true;
      connectionListener(_instance, _connected);
      print('websocket connected to  $_url');
      _channel.stream.listen(
        (message) {
          print('websocket receive $message');
          messageListener(_instance, message);
        },
        onDone: () {
          _connected = false;
          connectionListener(_instance, _connected);
          print('websocket closed');
        },
        onError: (error) {
          print('websocket error $error');
        },
      );
    } catch (e) {
      print('websocket exception $e');
      _connected = false;
      connectionListener(_connected);
    }
  }

  close() {
    if (_connected) {
      _channel.sink.close(status.normalClosure);
    }
  }

  bool send(String message) {
    try {
      if (_channel == null) throw ('_channel undefined');
      _channel.sink.add(message);
      return true;
    } catch (e) {
      return false;
    }
  }
}

И мой класс Item

class Item {
  final String time;

  Item({this.time});

  Item.fromJson(Map<String, dynamic> json) : time = json['time'];
  Map<String, dynamic> toJson() => {'time': time};
}

List<Item> items = [
  Item(time: '10:22'),
  Item(time: '11:22'),
];

Спасибо


person boub    schedule 12.04.2021    source источник


Ответы (1)


проблема в том, что вы вызываете addItem, который вызывает setState, однако, когда вы его вызывали, еще нет состояния

попробуйте переместить свои глобальные функции в класс состояния и вызвать их из initState

person Moaid ALRazhy    schedule 13.04.2021