Строит ли построитель потоков мои виджеты снова и снова без каких-либо изменений в потоке?

Отзывается конструктор потоков во Flutter. Не знаю почему. Я считаю, что проблема может заключаться в том, что у меня есть поставщик блоков в построителе потоков. Мой поток 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}

person GoPro    schedule 06.12.2018    source источник
comment
Это может быть не StreamBuilder, но если вызывается build() (тот, который содержит StreamBuilder), то виджеты, добавленные StreamBuilder, также создаются снова.   -  person Günter Zöchbauer    schedule 06.12.2018
comment
Я добавил свой первый оператор печати, чтобы проверить это. Моя сборка больше не вызывается. Я добавил комментарий. Проблема в моем стримбордере. Что-то там не так!   -  person GoPro    schedule 06.12.2018
comment
Тогда я уверен, что перестроение StreamBuilder может быть вызвано только событиями из потока.   -  person Günter Zöchbauer    schedule 06.12.2018
comment
Это также может быть так, что Stream излучает одно и то же значение снова и снова. ({idnumber: 10})   -  person Günter Zöchbauer    schedule 06.12.2018
comment
Вы можете фильтровать значения, если они равны предыдущему, используя такие вещи, как pub.dartlang.org/documentation/rxdart/latest/rx/Observable/   -  person Rémi Rousselet    schedule 06.12.2018
comment
Хорошо, если мой поток повторяет одно и то же значение снова и снова, я думаю, мне нужно отфильтровать его, как сказал Реми. Однако я не знаю, как это сделать. Ссылка, которой поделились, не дает мне достаточного представления об этом. Любой пример?   -  person GoPro    schedule 06.12.2018
comment
см. Stream#distinct() метод   -  person pskink    schedule 06.12.2018
comment
Большое спасибо, что сработало! Подборка сработала. Спасибо, Реми, Гюнтер, пскинк   -  person GoPro    schedule 06.12.2018
comment
конечно, добро пожаловать   -  person pskink    schedule 06.12.2018
comment
На самом деле мой вариант использования не поддерживает отдельные. Это была простая ошибка в подписке на поток и в конструкторе моего блока. тем не менее, я использовал отличный в другом месте, и я благодарен за информацию.   -  person GoPro    schedule 06.12.2018
comment
@GoPro, в чем заключалась простая ошибка?   -  person Jamie White    schedule 04.02.2019
comment
У меня была неправильная настройка подписки на поток, которая вызывалась в цикле. Извините за задержку с ответом @JamieWhite   -  person GoPro    schedule 01.03.2019


Ответы (1)


Я не могу воспроизвести эту проблему с базой точности 1: 1 из приведенных деталей. Аналогичным образом я столкнулся с тем, что сборка внутри StreamBuilder снова вызывается при ConnectionState изменениях.

Вот минимальное воспроизведение с использованием StreamBuilder, отправляющего HTTP-запрос. Пример HTTP-запроса здесь основан на этом руководстве по сети Flutter.

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 обсуждаются в этом документе.

person Omatt    schedule 11.11.2020