Flutter中StreamBuilder和流的问题接收重复的数据

问题描述

今天,我遇到了Streams和StreamBuilder的问题。 问题如下: 如果您有多个StreamBuilder小部件在侦听同一流,并且向其接收器中添加了数据,则该数据将通过该流以您拥有的StreamBuilder侦听器的数量流出,换句话说: 如果您有一个StreamController(或BehaviorSubject),即k个类型为StreamBuilder的小部件,并且尝试执行StreamController.sink.add(event),则此事件将通过该流k次,每个StreamBuilder发生一次。 这是否是预期的行为(预期的行为=输入一个事件并从另一侧监听一次,与侦听器的数量无关)?我能够将几乎所有的小部件树封装到一个StreamBuilder中,但是不能像第一种方法那样优化,因为您要渲染整个树而不是一些小节点小部件。 如果需要,我在此处留下了一些代码对其进行测试(此代码是对 Flutter create project_name 项目的修改)。 谢谢! (P.D:如果您仅在不使用StreamBuilder的情况下收听流,即streamController.stream.listen ..,则效果很好。)

import 'dart:async';

import 'package:Flutter/cupertino.dart';
import 'package:rxdart/subjects.dart';

class MyAppBloc with ChangeNotifier {
  int _currentIndex;
  BehaviorSubject<bool> _controller;

  MyAppBloc() {
    _currentIndex = 0;
    _controller = BehaviorSubject<bool>();
  }

  Stream<int> get currentIndex => _controller.stream.map<int>((event) {
        print('[event: $event]');
        _currentIndex++;
        return _currentIndex;
      });

  StreamSink<bool> get increment => _controller.sink;

  void close() {
    _controller.close();
  }
}
import 'package:Flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_project/bloc/my_app_bloc.dart';

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

  final String title;
  Widget leadingBuilder(MyAppBloc bloc) {
    return StreamBuilder<int>(
      initialData: 0,stream: bloc.currentIndex,builder: (BuildContext context,AsyncSnapshot<int> snapshot) {
        print('[leadingBuilderSnapshot: $snapshot]');
        return Text(snapshot.data.toString());
      },);
  }

  StreamBuilder<int> counterBuilder(MyAppBloc bloc) {
    return StreamBuilder<int>(
      initialData: 0,AsyncSnapshot<int> snapshot) {
        print('[counterBuilderSnapshot: $snapshot]');
        return Text(
          snapshot.data.toString(),style: Theme.of(context).textTheme.headline4,);
      },);
  }

  @override
  Widget build(BuildContext context) {
    print('[build]');
    final _bloc = Provider.of<MyAppBloc>(context);
    return Scaffold(
      appBar: AppBar(
        leading: Container(
          width: 30,height: 30,alignment: Alignment.center,child: leadingBuilder(_bloc),),title: Text(title),body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
            StreamBuilder<int>(
              initialData: 0,stream: _bloc.currentIndex,AsyncSnapshot<int> snapshot) {
                return Text('${snapshot.data}');
              },Text(
              'You have pushed the button this many times:',counterBuilder(_bloc),],floatingActionButton: FloatingActionButton(
        onpressed: () => _bloc.increment.add(true),tooltip: 'Increment',child: Icon(Icons.add),);
  }
}

解决方法

您必须使用2个流/接收器,并将增量放在get流之外。

import 'dart:async';
import 'package:rxdart/subjects.dart';

class Bloc {
  int _counter = 0;

  Bloc() {
    _controller.stream.listen(_incrementStream);
  }

  final _counterStream = BehaviorSubject<int>.seeded(0);

  Stream get presentCounter => _counterStream.stream;
  Sink get _addValue => _counterStream.sink;

  StreamController _controller = BehaviorSubject<bool>();
  StreamSink<bool> get incrementCounter => _controller.sink;

  void _incrementStream(data) {
    _counter += 1;
    _addValue.add(_counter);
  }

  void dispose() {
    _counterStream.close();
    _controller.close();
  }
}



import 'package:flutter/material.dart';
import 'package:increment/bloc.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',theme: ThemeData(
        primarySwatch: Colors.blue,visualDensity: VisualDensity.adaptivePlatformDensity,),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> {
  Bloc _bloc = Bloc();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
            Text(
              'You have pushed the button this many times:',StreamBuilder<int>(
                stream: _bloc.presentCounter,builder: (context,snapshot) {
                  return Text(
                    '${snapshot.data}',style: Theme.of(context).textTheme.headline4,);
                }),SizedBox(
              height: 60,],floatingActionButton: FloatingActionButton(
        onPressed: () {
          _bloc.incrementCounter.add(true);
        },tooltip: 'Increment',child: Icon(Icons.add),// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
,

由于# Generate a random AES Encryption Key. $AESKey = New-Object Byte[] 32 [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey) # Store the AESKey into a file. This file should be protected! (e.g. ACL on the file to allow only select people to read) Set-Content $AESKeyFilePath $AESKey # Any existing AES Key file will be overwritten $password = $passwordSecureString | ConvertFrom-SecureString -Key $AESKey Add-Content $credentialFilePath $password # To re-read the password,the following is done: $username = "reasonable.admin@acme.com.au" $AESKey = Get-Content $AESKeyFilePath $pwdTxt = Get-Content $SecurePwdFilePath $securePwd = $pwdTxt | ConvertTo-SecureString -Key $AESKey $credObject = New-Object System.Management.Automation.PSCredential -ArgumentList $username,$securePwd 是一个吸气剂,而您正在使用currentIndex,因此每次都会创建一个新的流 您致电map()bloc.currentIndex会听。

因此,在原始代码中,实际上有1 StreamBuilder和k StreamControlller。 (k:Streams的数量)

要解决您的问题,您可以创建一个eventController,并在一个块内侦听它以执行逻辑。 (仅从bloc本身监听eventStream,它将仅创建一次)

例如:

StreamBuilder

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...