3

guys. I am using StreamBuilder dealing with asynchronous data.

Here is a demo that a button on the first page, click the button will navigate to the second page. The full code is below.

import 'package:flutter/material.dart';
import 'dart:async' show StreamController;

void main() {
  runApp(
    new MaterialApp(
      title: 'First Page',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new FirstPage(),
    ),
  );
}

class FirstPage extends StatelessWidget {
  final StreamController<String> _streamController = StreamController<String>();

  @override
  Widget build(BuildContext context) {
    print('first page start to build ..................');
    StreamBuilder builder = new StreamBuilder(
        stream: _streamController.stream,
        builder: (context, asyncSnapshot) {
          if (asyncSnapshot.hasData) {
            print('first page data returned ..................');
            return RaisedButton(
              child: Text('go to the second page'),
              onPressed: () {
                print('navigate to second page ..................');
                  Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
            );
          } else {
            return Text('waitting to update');
          }
        });
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('First Page'),
      ),
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('update state'),
            onPressed: () {
              _streamController.add('hello world');
            },
          ),
          builder,
        ],
      ),
    );
  }

  dispose() {
    _streamController.close();
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('second page start to build ..................');
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Second Page'),
      ),
      body: Text('this is second page'),
    );
  }
}

Here are the operation steps:

  1. click the 'update state ' button on the first page.
  2. the button 'go to the second page' will show.
  3. click 'go to the second page' button will navigate to the second page.
  4. then click the button in the left corner of the second page to go back to the first page.

The console will show something like that:

I/flutter ( 3674): first page start to build ..................
Reloaded 1 of 487 libraries in 1,734ms.
I/flutter ( 3674): first page data returned ..................
I/flutter ( 3674): navigate to second page ..................
I/flutter ( 3674): second page start to build ..................
I/flutter ( 3674): first page data returned ..................
I/flutter ( 3674): first page data returned ..................

My question is:

  1. The first page will build again after the second page build. Why?
  2. And when I back to the first page, the first page will build again, is it normal?

Please help me.

and1990
  • 55
  • 1
  • 9

1 Answers1

3

This is the expected behavior.

The number of times a widget is built should never change the behavior of an application, and it at most a performance optimization.

If this is causing you any kind of issue, then you're likely doing something wrong inside build method. In which case, you might want to read How to deal with unwanted widget build?

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • hey Rémi, but why << first page start to build >> is not printed if the FirstPage widget is rebuilt when you go to the SecondPage , only <> is printed. – diegoveloper Jan 13 '19 at 18:16
  • Yes but it's purely optional. It shouldn't change the behavior of your app. In React, in development they even randomly call their "build" equivalent for no reason, just to verify you're following this rule. – Rémi Rousselet Jan 13 '19 at 18:20
  • but that's weird, because the build method wasn't called (what was expected) , only the content inside the Stream. – diegoveloper Jan 13 '19 at 18:24
  • @diegoveloper Hi. I had the same questions as you before. Then I checked the StreamBuilder implementation, it extends StatefulWidget. The build method will call when you use StatefulWidget if you use StatelessWidget it won't. So, I guess the first page build method didn't call, because the first page extends StatelessWidget. StreamBuilder extends StatefulWidget cause The StreamBuilder called again. This is just my guess, maybe it's wrong. If you find out the reason, please let me know. Thanks. – and1990 Jan 14 '19 at 02:39
  • 1
    It has nothing to do with this. It's because the reference to `home` widget never changes, because it's `home: Home()`. if you changed it to using `routes` instead, such as `routes: { '/': (context) => Home() }` then you'd have home rebuilding – Rémi Rousselet Jan 14 '19 at 02:50
  • @RémiRousselet That means home rebuilds and the StreamBuilder will rebuild as well - right. (Hard to avoid if you use the Navigation) That is not a problem in most cases but e.g I want to show a Dialog the Dialog will be shown again even if the state did not change. What is the workaround? – Ride Sun Apr 23 '19 at 22:55