简体   繁体   English

StreamBuilder 在构建时被多次调用

[英]StreamBuilder being called numerous times when in build

I have an application with multiple indexes on a navigation view, when I first load the app, as expected the StreamBuilder is called two times.我有一个导航视图上有多个索引的应用程序,当我第一次加载应用程序时,正如预期的那样,StreamBuilder 被调用了两次。 however, when I navigate to another index and back the build with the stream builder seems to be calling the stream builder to redownload all of the items inside of it.但是,当我导航到另一个索引并使用 stream 构建器返回构建时,似乎正在调用 stream 构建器来重新下载其中的所有项目。 I am worried this is going to consume all of my firebase data if this loop is ran for too long of a period.如果此循环运行时间过长,我担心这会消耗我所有的 firebase 数据。 How could I restructure to stop the StreamBuilder from being called many times when switching pages.切换页面时如何重组以阻止 StreamBuilder 被多次调用。 Note, I even save the state of this index when I switch and come back.请注意,当我切换并返回时,我什至保存了此索引的 state。

My build method:我的构建方法:

@override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
        stream: Firestore.instance
            .collection("posts/player/post")
            .orderBy("time", descending: true)
            .snapshots()
            .take(2),
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (!snapshot.hasData) return const Text('Loading...');
          final int highLightCount = snapshot.data.documents.length;
          return new StreamBuilder<QuerySnapshot>(
              stream: Firestore.instance
                  .collection("posts/player/post")
                  .snapshots(),
              builder: (BuildContext context,
                  AsyncSnapshot<QuerySnapshot> snapshot) {
                if (!snapshot.hasData)
                  return new Text("There are no current posts");
                return new ListView(
                  physics: const AlwaysScrollableScrollPhysics(),
                  scrollDirection: Axis.vertical,
                  shrinkWrap: true,
                  children: getPostItems(snapshot),
                );
              });
        });
  }

When I switch it is calling the getPostItem(snaphot) that is being called nearly nonstop, how could I prevent this from being called and consuming my data, or, prevent the StreamBuilder from changing unless something actually updates?当我切换它时,它正在调用几乎不间断地调用的 getPostItem(snaphot),我怎样才能防止它被调用并消耗我的数据,或者,除非实际更新,否则防止 StreamBuilder 发生变化?

The rest of the important code: rest的重要代码:

getPostItems(AsyncSnapshot<QuerySnapshot> snapshot) {
    return snapshot.data.documents.map((doc) => getListItem(doc)).toList();
  }

  Widget getListItem(var doc) {
    getProfUrl(doc);
    getDownUrl(doc);

    print("item hit");

    print("user: " + doc["user"] + "- current: " + widget.auth.getUserId());
    if (doc["user"] != widget.auth.getUserId()) {
      print("will show");
      if (doc["type"] == "image") {
        return new Column(
          children: <Widget>[
            new ListTile(
                title: new Text(doc["title"]),
                subtitle: new Text(doc["description"].toString()),
                leading: new Container(
                    width: 44.0,
                    height: 44.0,
                    decoration: new BoxDecoration(
                      shape: BoxShape.circle,
                      image: new DecorationImage(
                          fit: BoxFit.fill, image: NetworkImage(profUrl)),
                    ))),
            new Padding(
              padding: EdgeInsets.fromLTRB(4, 4, 4, 4),
              child: new Center(
                child: new AspectRatio(
                  aspectRatio: 1 / 1,
                  child: new Container(
                    decoration: new BoxDecoration(
                        image: new DecorationImage(
                      fit: BoxFit.fill,
                      alignment: FractionalOffset.topCenter,
                      image: new NetworkImage(downUrl),
                    )),
                  ),
                ),
              ),
            ),
          ],
        );
      } else {
        VideoPlayerController _controller = VideoPlayerController.network(
            'http://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4')
          ..initialize().then((_) {
            // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
            setState(() {});
          });

        return new Column(children: <Widget>[
          new ListTile(
              title: new Text(doc["title"]),
              subtitle: new Text(doc["description"].toString()),
              leading: new Container(
                  width: 44.0,
                  height: 44.0,
                  decoration: new BoxDecoration(
                    shape: BoxShape.circle,
                    image: new DecorationImage(
                        fit: BoxFit.fill, image: NetworkImage(profUrl)),
                  ))),
          new Padding(
            padding: EdgeInsets.fromLTRB(4, 4, 4, 4),
            child: new Center(
              child: new AspectRatio(
                aspectRatio: 500 / 500,
                child: VideoPlayer(_controller),
              ),
            ),
          ),
        ]);
      }
    }
  }

In order to reduce the number of times that the Stream is being created, you could move its initialisation into the initState method of the State class.为了减少Stream的创建次数,您可以将其初始化移动到State class 的initState方法中。

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  Stream<QuerySnapshot> _outerStream;
  Stream<QuerySnapshot> _innerStream;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _outerStream,
      builder: (context, snapshot) {
        if (!snapshot.hasData) return const Text('Loading...');
        final int highLightCount = snapshot.data.documents.length;
        return StreamBuilder<QuerySnapshot>(
          stream: _innerStream,
          builder: (context, snapshot) {
            if (!snapshot.hasData) return Text('There are no current posts');
            return ListView(
              physics: const AlwaysScrollableScrollPhysics(),
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              children: getPostItems(snapshot),
            );
          },
        );
      },
    );
  }

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

    _outerStream = Firestore
        .instance
        .collection('posts/player/post')
        .orderBy('time', descending: true)
        .snapshots()
        .take(2);

    _innerStream = Firestore
        .instance
        .collection('posts/player/post')
        .snapshots();
  }
}

Alternatively, if you would like to create the Stream once during the lifetime of the application, then you could use a StreamProvider to provide the Stream .或者,如果您想在应用程序的生命周期内创建一次Stream ,那么您可以使用StreamProvider来提供Stream

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StreamProvider<QuerySnapshot>(
          create: (context) {
            return Firestore.instance.collection('posts/player/post').snapshots();
          },
        ),
      ],
      child: MaterialApp(
        home: MyPage(),
      ),
    );
  }
}

class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final snapshot = context.watch<QuerySnapshot>();

    return Scaffold(
      body: snapshot == null
          ? Text('There are no current posts')
          : ListView(
              physics: const AlwaysScrollableScrollPhysics(),
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              children: getPostItems(snapshot),
            ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM