flutter - setState 不会导致 UI 刷新

标签 flutter setstate

使用有状态的小部件,我有这个构建功能:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Row(
          children: [
            Icon(MdiIcons.atom),
            Text("Message Channel")
          ],
        )
      ),

      body: compileWidget(context),

      bottomSheet: Row(
        children: [
          Expanded(
              child: DefaultTextFormField(true, null, hintText: "Message ...", controller: messageField)
          ),

          IconButton(
              icon: Icon(Icons.send),
              onPressed: onSendPressed
          )
        ],
      ),
    );
  }

正如您在正文中看到的,有一个 compileWidget 函数定义为:

  FutureBuilder<Widget> compileWidget(BuildContext context) {
    return FutureBuilder(
      future: createWidget(context),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            print("DONE loading widget ");
            return snapshot.data;
          } else {
            return Container(
              child: Center(
                child: CircularProgressIndicator()
              ),
            );
          }
        }
    );
  }

反过来,createWidget 函数如下所示:

List<Widget> bubbles;

  Future<Widget> createWidget(BuildContext context) async {
    await updateChatList();
    // when working, return listview w/ children of bubbles
    return Padding(
      padding: EdgeInsets.all(10),
      child: ListView(
        children: this.bubbles,
      ),
    );
  }

// update chat list below

  Future<void> updateChatList({Message message}) async {
    if (this.bubbles != null) {
      if (message != null) {
        print("Pushing new notification into chat ...");
        this.bubbles.add(bubbleFrom(message));
      } else {
        print("Update called, but nothing to do");
      }
    } else {
      var initMessages = await Message.getMessagesBetween(this.widget.implicatedCnac.implicatedCid, this.widget.peerNac.peerCid);
      print("Loaded ${initMessages.length} messages between ${this.widget.implicatedCnac.implicatedCid} and ${this.widget.peerNac.peerCid}");
      // create init bubble list

      this.bubbles = initMessages.map((e) {
        print("Adding bubble $e");
        return bubbleFrom(e);
      }).toList();
      print("Done loading bubbles ...");
    }
  }

聊天气泡以良好的顺序填充屏幕。但是,一旦有新消息进入并被以下人员接收:

  StreamSubscription<Message> listener;

  @override
  void initState() {
    super.initState();

    this.listener = Utils.broadcaster.stream.stream.listen((message) async {
      print("{${this.widget.implicatedCnac.implicatedCid} <=> ${this.widget.peerNac.peerCid} streamer received possible message ...");
      if (this.widget.implicatedCnac.implicatedCid == message.implicatedCid && this.widget.peerNac.peerCid == message.peerCid) {
        print("Message meant for this screen!");
        await this.updateChatList(message: message);
        setState(() {});
      }
    });
  }

“此屏幕的消息!”打印,然后在 updateChatList 中打印“Pushing new notification into chat ...”,这意味着气泡已添加到数组中。最后,调用了 setState,但是附加的气泡并未被渲染。这里可能出了什么问题?

最佳答案

首先,让我解释一下如何setState根据此工作 link .

每当您更改 State 的内部状态时对象,在传递给 setState 的函数中进行更改。调用setState通知框架此对象的内部状态已更改,可能会影响此子树中的用户界面,这会导致框架为此安排构建 State对象。

就你而言,我想说这只是一个约定。您可以在有状态类中定义消息对象,并在监听器和您的 setstate 内更新它。像这样:

setState(() { this.message = message; });

警告:

在进行任何更改之前,您需要检查此问题

Usage of FutureBuilder with setState

因为使用setsteteFutureBuilder可以在 StatefulWidget 中进行无限循环这会降低性能和灵活性。也许,您应该改变设计屏幕的方法,因为 FutureBuilder每次尝试获取数据时都会自动更新状态。

更新:

对于您的问题,有更好的解决方案。因为您使用流来读取消息,所以可以使用 StreamBuilder而不是听众和 FutureBuilder 。它为提供数据流的服务带来了更少的实现和更高的可靠性。每次StreamBuilder接收来自 Stream 的消息,它将显示您想要的任何数据快照。

关于flutter - setState 不会导致 UI 刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66552324/

相关文章:

Flutter:为什么 setState(( ) { }) 一次又一次地设置数据

javascript - React setstate 方法的回调未触发

Flutter:可以检测抽屉何时打开?

Flutter - 如何在 TabBarView 的主体内导航?

react-hooks - React Form UI 未正确反射(reflect)状态变化

React-Native this.setState() 不起作用

javascript - 在reactjs中删除重复项后如何从状态值和setstate创建数组

regex - hh :mm:ss format in TextFormField or TextField without using pickers 中的 Flutter 输入时间

flutter - BannerAd.dispose 不工作 Flutter Admob

android - Flutter/Dart如何将sizedbox居中到屏幕的顶部中心?