【问题标题】:Does stream builder build my widgets again and again without any change in stream?流构建器是否一次又一次地构建我的小部件而流没有任何变化?
【发布时间】:2019-05-08 12:07:30
【问题描述】:

Flutter 中的 Stream builder 正在被召回。我不确定为什么。我相信问题可能是我在流构建器中有一个集团提供者。我的流 dataBloc.dataStream 没有改变,导致流构建器再次构建。不确定,我做错了什么。流构建器是否一次又一次地构建我的小部件而流没有任何变化。显然这不是真的!对吧?

Widget build(context) {
        final DataBloc dataBloc = DataBlocProvider.of(context);
        print("dropdown build called again");                         
        // this doesn't print recursively so this is perfect.
        // So my build is not getting called again. 

        return StreamBuilder(
            stream: dataBloc.dataStream,
            builder: (context, snapshot) {

              //ToDo remove prints
              print("dropdown ${snapshot.data}");                     
             // there is no change in snapshot.data, however print is getting called recursively. This is bad and wrong
             // so my stream builder is getting called again, and this is wrong


              String key = dataElement.conditionalField;
              String _valueArray = dataElement.conditionalValues.toString();
              String conditionalValue =
                  _valueArray.substring(1, _valueArray.length - 1);
              Map<String, String> dataMap = snapshot.hasData ? snapshot.data : {};
              bool isVisible = true;

              if (key != "" &&
                  dataMap.containsKey(key) &&
                  dataMap[key] == conditionalValue.toString()) {
                isVisible = true;
              } else if (key != "") {
                isVisible = false;
              }

              return Visibility(
                child: BlocDropDownProvider(
                  fieldName: dataElement.key,
                  dataBloc: dataBloc,
                  child: Card(
                    color: Colors.grey[100],
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: <Widget>[
                        label,
                        new Container(
                          height: 8.0,
                        ),
                        dropDown,
                      ],
                    ),
                  ),
                ),
                visible: isVisible? true:false,
              );

控制台的输出是:

I/flutter (14422): dropdown {idnumber: 10}
I/flutter (14422): dropdown {idnumber: 10}

【问题讨论】:

  • 它可能不是StreamBuilder,但如果build()(包含StreamBuilder的那个)被调用,那么StreamBuilder添加的小部件也会重新构建。
  • 我添加了我的第一个打印语句来检查。我的构建不再被调用。我已添加评论。问题是我的流生成器​​。那里有些不对劲!
  • 这也可能是 Stream 一遍又一遍地发出相同的值。 ({idnumber: 10})
  • 您可以使用pub.dartlang.org/documentation/rxdart/latest/rx/Observable/…等内容过滤与前一个值相等的值
  • Stream#distinct()方法

标签: flutter flutter-layout flutter-dependencies flutter-sliver


【解决方案1】:

我无法从给定的详细信息中以 1:1 的准确度复制这个问题。我遇到的类似情况是StreamBuilder 内的构建在ConnectionState 更改时再次被调用。

这是使用 StreamBuilder 发送 HTTP 请求的最小重现。此处的 HTTP 请求示例基于此 Flutter Networking guide

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final streamController = StreamController();

  @override
  void initState() {
    super.initState();
    fetchAlbum().then((response) => streamController.add(response));
  }

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

  @override
  Widget build(BuildContext context) {
    debugPrint('build');
    return StreamBuilder(
      stream: streamController.stream,
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        debugPrint('Stream $snapshot');
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: snapshot.hasData
                ? Text('Album ${snapshot.data.title}')
                : Text('Waiting...'),
          ),
        );
      },
    );
  }

  Future<Album> fetchAlbum() async {
    final response =
        await http.get('https://jsonplaceholder.typicode.com/albums/1');

    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      return Album.fromJson(jsonDecode(response.body));
    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      throw Exception('Failed to load album');
    }
  }
}

class Album {
  final int userId;
  final int id;
  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

再一次,我建议不要太在意构建成本,只要构建中的小部件是可管理的。有关 Flutter 最佳实践的更多详细信息,请参阅 doc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-04
    • 2022-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 2022-06-22
    相关资源
    最近更新 更多