如何使用 StreamBuilder 执行不同值的网络请求

How to use StreamBuilder to perform network requests with different values

我正在使用 FutureBuilder 小部件根据未来 counter 的值呈现 Text,当我单击浮动操作按钮时,我再次调用未来一个不同的值。但是我需要在单击按钮后执行 setState 以刷新 UI,这对于屏幕上的几个小部件来说没问题,但调用 setState 也会重建其他小部件.


class _MyHomePageState extends State<MyHomePage> {
  Future counter;

  @override
  void initState() {
    super.initState();
    counter = counterFuture(4);
  }

  //This would be a network request with a specific value
  Future<int> counterFuture(int i) async {
    return await Future.value(i);
  }

  _changeCounter(int i) {
    setState(() {
      counter = counterFuture(i);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FutureBuilder<int>(
              future: counter,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text(snapshot.data.toString());
                }
                return Text('loading');
              },
            ),
             ...other widgets
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        //tap button to request with a different value
        onPressed: () => _changeCounter(9),
      ),
    );
  }
}

我的问题是如何使用 Streams 和 StreamBuilder 仅呈现和更新 Text 小部件来实现此目的?

您可以使用 StreamController 轻松做到这一点。 查看下面的代码片段:

class _MyHomePageState extends State<MyHomePage> {
  int counter;
  StreamController controller = StreamController<int>();

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

  initialize() async {
    counter = await counterFuture(4);
    controller.add(counter);
  }

  @override
  void dispose() {
    controller.close();
   super.dispose();
  }

  //This would be a network request with a specific value
  Future<int> counterFuture(int i) async {
    return await Future.value(i);
  }

  _changeCounter(int i) async {
    counter = await counterFuture(i);
    controller.add(counter);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              StreamBuilder<int>(
                stream: controller.stream,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text(snapshot.data.toString());
                  }
                  return Text('loading');
                },
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
           //tap button to request with a different value
         onPressed: () => _changeCounter(9)),
      ),
    );
  }
}