避免StreamBuilder刷新Flutter中运行的SetState

时间:2019-11-27 15:17:46

标签: flutter

我有一个页面,其中显示2个元素,它们都是不同的StreamBuilder,但第二个元素取决于第一个元素。 为了更加清楚,我显示以下内容:

Firebase documents (list)
Firebase user

如果我们退出,两个StreamBuilder都会消失。很好,但是当我需要从列表中选择一个文档时,我的问题就来了:

return ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(set["title"]),
selected: _selected[index],
trailing: Badge(
   badgeColor: Colors.grey,
   shape: BadgeShape.circle,
   toAnimate: true,
onTap: () => setState(() => _selected[index] = !_selected[index]),
);                     

每次我执行SetState()时,我都会刷新第一个StreamBuilder(不确定原因),然后刷新第二个。{p>

这是列表小部件:

Widget _mySetsLists(BuildContext context) {
    List<bool> _selected = List.generate(20, (i) => false);

    return StreamBuilder(
      stream: FirebaseAuth.instance.onAuthStateChanged,
      builder: (context, snapshot) {
        FirebaseUser user = snapshot.data;
        if (snapshot.hasData) {
          return StreamBuilder(
            stream: Firestore.instance
                .collection('users')
                .document(user.uid)
                .collection('sets')
                .snapshots(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.hasData) {
                return new ListView.builder(
                  shrinkWrap: true,
                  itemCount: snapshot.data.documents.length,
                  itemBuilder: (context, index) {
                    DocumentSnapshot set = snapshot.data.documents[index];
                    return ListTile(
                      leading: FlutterLogo(size: 40.0),
                      title: Text(set["title"]),
                      selected: _selected[index],
                      onTap: () => setState(() => _selected[index] = !_selected[index]),
                    );
                  },
                );
              } else {
                return Center(
                  child: new CircularProgressIndicator(),
                );
              }
            },
          );
        } else {
          return Text("loadin");
        }
      },
    );
  }
}

这是用户个人资料:

class UserProfileState extends State<UserProfile> {
  @override
  Widget build(BuildContext context) {
    return SliverList(
      delegate: SliverChildListDelegate(
        [
          _mySetsLists(context),
          Divider(),
          StreamBuilder<FirebaseUser>(
            stream: FirebaseAuth.instance.onAuthStateChanged,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.active) {
                FirebaseUser user = snapshot.data;
                if (user == null) {
                  return Text('not logged in');
                }
                return ListTile(
                  leading: CircleAvatar(
                    backgroundImage: NetworkImage(
                      user.photoUrl,
                    ),
                  ),
                  title: Text(user.displayName),
                  subtitle: Text(user.email),
                  trailing: new IconButton(
                      icon: new Icon(Icons.exit_to_app),
                      highlightColor: Colors.pink,
                      onPressed: () {
                        authService.signOut();
                      }),
                );
              } else {
                return Text("loading profile"); // <---- THIS IS WHAT I SEE
              }
            },
          ),
        ],
      ),
    );
  }

2 个答案:

答案 0 :(得分:0)

我也遇到了同样的困难,但这是我使用的技巧

var itemsData = List<dynamic>();
  var _documents = List<DocumentSnapshot>();
 @override
  void initState() {
    // TODO: implement initState
    super.initState();
getData();


  }
getData(){
Firestore.instance
      .collection('users')
      .document(currentUser.uid)
      .collection('set')
      .getDocuments()
      .then((value) {
    value.documents.forEach((result) {

      setState(() {
        _documents.add(result);
        itemsData.add(result.data);
      });


    });
  });
}

替换您的listview构建器将是这样

ListView.builder(
                  shrinkWrap: true,
                  itemCount: _documents.length,
                  itemBuilder: (context, index) {
return ListTile(
title:Text(itemsData[index]['name'])
)


})

希望有帮助!

答案 1 :(得分:0)

如果您假装使用流大量使用 setstat,您可以在本地下载数据。所以每次重新加载不会再次下载数据,而只是显示本地数据。

第一步:声明将在本地存储数据的变量。

QuerySnapshot? querySnapshotGlobal;

然后在读取streamData的地方,先检查一下刚才声明的本地数据是否为空:

//check if its empty
if(querySnapshotGlobal==null)
              //as its empty, we will download it from firestore
              StreamBuilder<QuerySnapshot>(
              stream: _queryAlunos.snapshots(),
              builder: (context, stream){

                if (stream.connectionState == ConnectionState.waiting) {
                  return Center(child: CircularProgressIndicator());
                }

                else if (stream.hasError) {
                  return Center(child: Text(stream.error.toString()));
                }


                else if(stream.connectionState == ConnectionState.active){

                  //QuerySnapshot? querySnapshot = stream.data;
                  //instead of save data here, lets save it in the variable we declared
                  querySnapshotGlobal = stream.data;

                  return querySnapshotGlobal!.size == 0
                      ? Center(child: Text('Sem alunos nesta turma'),)
                      : Expanded(
                    child: ListView.builder(
                      itemCount: querySnapshotGlobal!.size,
                      itemBuilder: (context, index){

                        Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();

                        //let it build
                        return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);

                      },
                    ),
                  );

                }

                return CircularProgressIndicator();

              },
            )
            else
              //now, if you call setstate, as the variable with the data is not empty, will call it from here e instead of download it again from firestore, will load the local data
              Expanded(
                child: ListView.builder(
                  itemCount: querySnapshotGlobal!.size,
                  itemBuilder: (context, index){

                    Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();

                    return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);

                  },
                ),
              ),

希望它可以帮助您节省一些钱!