流构建器是否可以一次又一次构建我的窗口小部件,而流中没有任何变化吗?

时间:2018-12-06 18:14:50

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

Flutter中的流生成器​​被召回。我不知道为什么。我相信问题可能是我在流构建器中有一个bloc提供程序。我的流dataBloc.dataStream没有更改,导致streambuilder再次构建。不知道,我在做什么错。流构建器是否一次又一次构建我的窗口小部件,而流中没有任何更改。显然那是不对的!对吧?

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}

1 个答案:

答案 0 :(得分:0)

根据给出的详细信息,我无法真正以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'],
    );
  }
}

enter image description here

再说一次,我建议不要太在意构建成本,只要构建中的Widget是可管理的即可。此doc中讨论了有关Flutter最佳做法的更多详细信息。