Flutter中如何在listview中刷新数据

3

更新 这是StreamBuilder的代码: 我目前正在尝试使用定时器运行Stream.fromFuture来更新数据,但会出现闪烁和滚动问题。

new StreamBuilder(
                initialData: myInitialData,
                stream: msgstream,
                builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                      return new Text('Waiting to start');
                    case ConnectionState.waiting:
                      return new Text('');
                    default:
                      if (snapshot.hasError) {
                        return new Text('Error: ${snapshot.error}');
                      } else {
                        myInitialData = snapshot.data;
                        return new RefreshIndicator(
                            child: new ListView.builder(
                              itemBuilder: (context, index) {
                                Stream<List<Map>> msgstream2;
                                Future<List<Map>> _responseDate = ChatDB.instance.getMessagesByDate(snapshot.data[index]['msgkey'], snapshot.data[index]['msgdate']);
                                msgstream2 = new Stream.fromFuture(_responseDate);
                                return new StreamBuilder(
                                  initialData: myInitialData2,
                                  stream: msgstream2,
                                  builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
                                    switch (snapshot.connectionState) {
                                      case ConnectionState.none:
                                        return new Text('Waiting to start');
                                      case ConnectionState.waiting:
                                        return new Text('');
                                      default:
                                        List messList;
                                        var mybytes;
                                        File myimageview;
                                        Image newimageview;
                                        String imgStr;
                                        String vidStr;
                                        String vidimgstr;
                                        myInitialData2 = snapshot.data;
                                        List<dynamic> json = snapshot.data;
                                        List messagelist = [];
                                        json.forEach((element) {

                                          DateTime submitdate =
                                          DateTime.parse(element['submitdate']).toLocal();
                                          String myvideo = (element['chatvideo']);
                                          String myimage = element['chatimage'];
                                          String myvideoimage = element['chatvideoimage'];
                                          File imgfile;
                                          File vidfile;
                                          File vidimgfile;
                                          bool vidInit = false;
                                          Future<Null> _launched;
                                          String localAssetPath;
                                          String localVideoPath;
                                          String mymessage = element['message'].replaceAll("[\u2018\u2019]", "'");
                                          //print('MYDATE: '+submitdate.toString());
                                          _checkFile(File file) async {
                                            var checkfile = await file.exists();
                                            print('VIDEXISTS: '+checkfile.toString());
                                          }
                                          Future<Null> _launchVideo(String url, bool isLocal) async {
                                            if (await canLaunchVideo(url, isLocal)) {
                                              await launchVideo(url, isLocal);
                                            } else {
                                              throw 'Could not launch $url';
                                            }
                                          }
                                          void _launchLocal() =>
                                              setState(() => _launched = _launchVideo(localVideoPath, true)
                                              );

                                          Widget _showVideo() {
                                            return new Flexible(
                                                child: new Card(
                                                  child: new Column(
                                                    children: <Widget>[
                                                      new ListTile(subtitle: new Text('Video'), title: new Text(element['referralname']),),
                                                      new GestureDetector(
                                                        onTap: _launchLocal,
                                                        child: new Image.file(
                                                          vidimgfile,
                                                          width: 150.0,
                                                        ),
                                                      ),
                                                    ],
                                                  ),
                                                )
                                            );
                                          }

                                          if (myimage != "") {
                                            imgStr = element['chatimage'];
                                            imgfile = new File(imgStr);
                                          }
                                          if (myvideo != "") {
                                            vidStr = element['chatvideo'];
                                            vidimgstr = element['chatvideoimage'];
                                            vidimgfile = new File(vidimgstr);

                                            localVideoPath = '$vidStr';


                                          }

                                          _showLgPic() {
                                            Route route = new MaterialPageRoute(
                                              settings: new RouteSettings(name: "/ShowPic"),
                                              builder: (BuildContext context) => new ShowPic(
                                                image: imgfile,
                                              ),
                                            );
                                            Navigator.of(context).push(route);
                                          }

                                          Widget _showGraphic() {
                                            Widget mywidget;
                                            if (myimage != "") {
                                              mywidget = new GestureDetector(
                                                child: new Image.file(
                                                  imgfile,
                                                  width: 300.0,
                                                ),
                                                onTap: _showLgPic,
                                              );
                                            } else if (myvideo != "") {
                                              mywidget = _showVideo();
                                            } else {
                                              mywidget = new Container();
                                            }
                                            return mywidget;
                                          }

                                          messagelist.add(
                                            new Container(
                                              //width: 300.0,
                                              padding: new EdgeInsets.all(10.0),
                                              child: new Column(
                                                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                                                crossAxisAlignment: CrossAxisAlignment.stretch,
                                                mainAxisSize: MainAxisSize.min,
                                                children: <Widget>[
                                                  new Container(
                                                    padding: new EdgeInsets.only(bottom: 5.0),
                                                    child: new Row(
                                                      mainAxisSize: MainAxisSize.min,
                                                      children: <Widget>[
                                                        new CircleAvatar(
                                                          child: new Text(
                                                            element['sendname'][0],
                                                            style: new TextStyle(fontSize: 15.0),
                                                          ),
                                                          radius: 12.0,
                                                        ),
                                                        new Text('    '),
                                                        new Text(
                                                          element['sendname'],
                                                          style: new TextStyle(
                                                              fontSize: 15.0,
                                                              fontWeight: FontWeight.bold),
                                                        ),
                                                        new Text('    '),
                                                        new Text(
                                                          new DateFormat.Hm().format(submitdate),
                                                          style: new TextStyle(
                                                              color: Colors.grey, fontSize: 12.0),
                                                        ),

                                                      ],
                                                    ),
                                                  ),
                                                  new Row(
                                                    children: <Widget>[
                                                      new Text('          '),
                                                      new Flexible(
                                                        child: new Text(mymessage),
                                                      )
                                                    ],
                                                  ),
                                                  new Container(
                                                      width: 150.0,
                                                      child: new Row(
                                                        children: <Widget>[
                                                          new Text('          '),
                                                          _showGraphic()
                                                        ],
                                                      )),
                                                ],
                                              ),
                                            ),
                                          );
                                        });
                                        return new Column(children: messagelist);
                                    }
                                  }
                                );
                                /*return new MyChatWidget(
                                  datediv: snapshot.data[index]['msgdate'],
                                  msgkey: snapshot.data[index]['msgkey'],
                                );*/

                              },
                              //itemBuilder: _itemBuilder,
                              controller: _scrollController,
                              reverse: true,
                              itemCount: snapshot.data.length,
                            ),
                            onRefresh: _onRefresh
                        );
                      }

                  }
                }),

我从本地sqlite数据库开始使用一个名为Future>的对象。我将该future用于获取另一个名为Future>的对象中的数据。我使用Listview.builder构建小部件等...所有工作都很顺利,但需要实时刷新数据以显示收到的消息并更新到数据库中。我将futures转换为streams,并使用计时器来获得新数据,但是屏幕会闪烁,尽管数据已经刷新了,但不美观。
因此,我正在尝试找出一种更好的方法来更新数据,避免闪烁,并且不会影响用户在页面上滚动查看消息。
我目前执行这两个futures,因为其中一个用于在每个日期之间构建日期分隔符。我一直在考虑使用StreamController并订阅它,但不清楚如何更新控制器中的数据,因为当用户打开页面时数据需要全面并添加新消息进行同步。
因此,我一直在寻找类似于我发现的以下内容的解决方案:
class Server {
  StreamController<List<Map>> _controller = new StreamController.broadcast();
  void addMessage(int message) {
    var newmsg = await database.rawQuery('select c.*, date(submitdate, "localtime") as msgtime from v_groupchats g join chats c on c.id = g.id where (oid = $oid or prid = $prid) and c.msgkey not in (select msgkey from chatArchive) order by submitdate desc');
    _controller.add(message);
  }
  Stream get messages => _controller.stream;
}

以下内容并不完整,仅希望能为某些人提供一些想法。

非常感谢您的帮助。


你能提供一下你的Flutter列表实现吗?因为很可能问题就出在这里。 - Rémi Rousselet
代码已经更新。 - Robert
滚动会“刷新”状态,因此可能闪烁效果与图像缓存有关。您应该检查这种类型的问题。 - stuckedoverflow
1个回答

5
这种闪烁很可能是由以下原因造成的:
case ConnectionState.waiting:
  return new Text('');

因为每次获取数据时,你的流会在进入 ConnectionState.done 状态前短暂地进入到 ConnectionState.waiting 状态。而你所做的是告诉 UI 在每次获取数据时显示基本上什么都没有的 Text('')。即使它只需要50毫秒,对于人眼来说也是可以察觉到的...
如果你不介意流在获取数据时出现这种情况,那么就移除这个检查。否则,你可以将布局更改为Stack并在某个地方叠加一个加载动画,或者只是一些指示当前正在获取数据的东西。
(请注意,我通过模拟Future.delayed(const Duration(milliseconds: 50), () => data)测试了你的设置,并且我们可以感知得更快

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接