首页 > 解决方案 > 无法从静态方法调用 Flutter Stateful Widget 的 setState

问题描述

我在显示列表视图的地方有以下代码,并且此列表视图从列表中获取数据,该列表可以onConnect()STOMP. 所以这个 onConnect 方法应该是静态的。

现在,当我从 WebSocket 接收数据时,会调用这个 onConnect 方法,它将值插入到列表中。但是列表视图没有得到更新。我无法调用setState(),以便使用新数据重新渲染小部件,因为此onConnect()方法是静态的。

对此的任何解决方案。

List<ChatEntity> chats;
String chatRoomId;
String currentUserEmail;

class Chat extends StatefulWidget {

  Chat(String chatRoomIdC, String currentUserEmailC) {
    chatRoomId = chatRoomIdC;
    currentUserEmail = currentUserEmailC;
  }

  @override
  _ChatState createState() => _ChatState();
}

class _ChatState extends State<Chat> {
  TextEditingController messageEditingController = new TextEditingController();
 
  _ChatState() {
    client.activate();
  }

  StompClient client = StompClient(
    config: StompConfig(
        url: 'ws://localhost:8080/ws',
        onConnect: onConnectCallback,
        onWebSocketError: (dynamic error) => print(error.toString())),
  );

  static onConnectCallback(StompClient client, StompFrame connectFrame) {
    client.subscribe(
        destination: '/topic/messages/$chatRoomId',
        headers: {},
        callback: (frame) {
          response(frame);
        });
  }

  static response(StompFrame frame) {
    String response = frame.body;
    final parsed = json.decode(response).cast<Map<String, dynamic>>();
    chats.insert(
        0,
        parsed
            .map<ChatEntity>((json) => ChatEntity.fromJson(json))
            .toList()[0]);

 // call setState here to re- render the widget
  }

  Widget chatMessages() {
    return ListView.builder(
        reverse: true,
        itemCount: chats == null ? 0 : chats.length,
        itemBuilder: (context, index) {
          return MessageTile(
            message: chats[index].message,
            sendByMe: currentUserEmail == chats[index].sentBy,
          );
        });
  }

  addMessage() {
    if (messageEditingController.text.isNotEmpty) {
      Map<String, dynamic> chatMessageMap = {
        "chatroomId": chatRoomId,
        "sentBy": currentUserEmail,
        "message": messageEditingController.text
      };
      client.send(
          destination: '/app/chat',
          body: jsonEncode(chatMessageMap),
          headers: {});

      setState(() {
        messageEditingController.text = "";
      });
    }
  }

  @override
  void initState() {
    DatabaseMethods.getChats(chatRoomId).then((val) {
      setState(() {
        chats = val;
      });
    });
    super.initState();
  }

// ignore the build method as it just contains a Scaffold.

标签: flutter

解决方案


为了使用或访问setState方法,您需要在实例方法内部,而不是静态(类)方法。因此responseonConnectCallback在这种情况下,方法不应该是静态的。因为StompClient引用了这些方法,所以我会在StompClient client实例化小部件时创建一个实例(即在构造函数中):

class _ChatState extends State<Chat> {
  TextEditingController messageEditingController = new TextEditingController();
  
  StompClient client;
 
  // Create a StompClient instance when creating new state
  _ChatState() {
    client = StompClient(
      config: StompConfig(
        url: 'ws://localhost:8080/ws',
        onConnect: onConnectCallback,
        onWebSocketError: (dynamic error) => print(error.toString())),
    );
    client.activate();
  }
 
  onConnectCallback(StompClient client, StompFrame connectFrame) {
    ...
  }

  response(StompFrame frame) {
    ...
    // HERE YOU SHOULD BE ABLE TO USE setState() METHOD
  }
...

推荐阅读