likes
comments
collection
share

flutter中如何更好的使用stream

作者站长头像
站长
· 阅读数 32

Flutter中的Stream是用于处理异步事件流的一种重要工具。Stream可以看作是一个异步数据序列,它能够按顺序提供多个异步事件。Flutter中的Stream主要用于处理连续的数据更新,比如网络请求的结果、用户输入的事件、传感器数据等。以下是对Flutter中Stream的详细说明,包括基础概念、常用方法、实际使用和高级用法。

基础概念

  • Stream:表示一个可以接收异步事件的数据源。可以生成一个或多个值。
  • StreamController:控制Stream,可以向其添加事件、错误以及关闭它。
  • StreamSubscription:表示对Stream的监听,可以用来取消订阅。
  • Sink:用来向Stream添加数据、错误、以及关闭。

常用方法

  • Stream.fromIterable:创建一个从Iterable中获取数据的Stream。
  • Stream.periodic:创建一个按周期生成数据的Stream。
  • StreamController:用于创建自定义Stream,允许手动添加数据。
  • StreamBuilder:Flutter提供的一个Widget,用于在构建Widget时监听Stream的数据变化。

示例代码

创建和监听Stream

  1. 使用StreamController创建和控制Stream

    dart
    复制代码
    import 'dart:async';
    
    void main() {
      // 创建StreamController
      final controller = StreamController<int>();
    
      // 获取Stream
      final stream = controller.stream;
    
      // 监听Stream
      stream.listen((data) {
        print('Received data: $data');
      });
    
      // 添加数据到Stream
      controller.sink.add(1);
      controller.sink.add(2);
      controller.sink.add(3);
    
      // 关闭Stream
      controller.close();
    }
    
  2. 使用StreamBuilder监听Stream并更新UI

    dart
    复制代码
    import 'dart:async';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: Text('StreamBuilder Example')),
            body: Center(
              child: CounterWidget(),
            ),
          ),
        );
      }
    }
    
    class CounterWidget extends StatefulWidget {
      @override
      _CounterWidgetState createState() => _CounterWidgetState();
    }
    
    class _CounterWidgetState extends State<CounterWidget> {
      final StreamController<int> _controller = StreamController<int>();
      int _counter = 0;
    
      void _incrementCounter() {
        _counter++;
        _controller.sink.add(_counter);
      }
    
      @override
      void dispose() {
        _controller.close();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            StreamBuilder<int>(
              stream: _controller.stream,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text('Counter: ${snapshot.data}');
                } else {
                  return Text('Counter: 0');
                }
              },
            ),
            ElevatedButton(
              onPressed: _incrementCounter,
              child: Text('Increment Counter'),
            ),
          ],
        );
      }
    }
    

高级用法

  1. Transforming Streams:使用mapwhere等方法对Stream的数据进行转换和过滤。

    dart
    复制代码
    final stream = Stream.fromIterable([1, 2, 3, 4, 5]);
    final transformedStream = stream.where((data) => data % 2 == 0).map((data) => 'Number $data');
    
    transformedStream.listen((data) {
      print(data); // 输出: Number 2, Number 4
    });
    
  2. Broadcast Streams:允许多个监听器同时监听一个Stream。

    dart
    复制代码
    final controller = StreamController<int>.broadcast();
    
    controller.stream.listen((data) => print('Listener 1: $data'));
    controller.stream.listen((data) => print('Listener 2: $data'));
    
    controller.sink.add(1);
    controller.sink.add(2);
    controller.sink.add(3);
    
    controller.close();
    
  3. Combining Streams:使用StreamZip等方法组合多个Stream的数据。

    dart
    复制代码
    import 'package:async/async.dart';
    
    final stream1 = Stream.fromIterable([1, 2, 3]);
    final stream2 = Stream.fromIterable(['A', 'B', 'C']);
    
    final combinedStream = StreamZip([stream1, stream2]);
    
    combinedStream.listen((data) {
      print('Combined data: $data'); // 输出: [1, A], [2, B], [3, C]
    });
    

使用场景

  1. 网络请求:在Flutter应用中,可以使用Stream处理网络请求的结果。例如,使用Stream来监听网络数据流,并通过StreamBuilder更新UI。

    dart
    复制代码
    import 'dart:async';
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    
    class DataFetcher {
      final StreamController<String> _controller = StreamController<String>();
    
      Stream<String> get stream => _controller.stream;
    
      Future<void> fetchData() async {
        final response = await http.get(Uri.parse('https://api.example.com/data'));
        if (response.statusCode == 200) {
          _controller.sink.add(response.body);
        } else {
          _controller.sink.addError('Failed to fetch data');
        }
      }
    
      void dispose() {
        _controller.close();
      }
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: Text('Stream Network Request Example')),
            body: Center(
              child: DataWidget(),
            ),
          ),
        );
      }
    }
    
    class DataWidget extends StatefulWidget {
      @override
      _DataWidgetState createState() => _DataWidgetState();
    }
    
    class _DataWidgetState extends State<DataWidget> {
      final DataFetcher _dataFetcher = DataFetcher();
    
      @override
      void initState() {
        super.initState();
        _dataFetcher.fetchData();
      }
    
      @override
      void dispose() {
        _dataFetcher.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return StreamBuilder<String>(
          stream: _dataFetcher.stream,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return CircularProgressIndicator();
            } else if (snapshot.hasError) {
              return Text('Error: ${snapshot.error}');
            } else if (snapshot.hasData) {
              return Text('Data: ${snapshot.data}');
            } else {
              return Text('No data');
            }
          },
        );
      }
    }
    
  2. 用户输入事件:可以使用Stream来处理用户输入事件,如文本框的输入变化。

    dart
    复制代码
    import 'dart:async';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: Text('Stream Input Example')),
            body: Center(
              child: InputWidget(),
            ),
          ),
        );
      }
    }
    
    class InputWidget extends StatefulWidget {
      @override
      _InputWidgetState createState() => _InputWidgetState();
    }
    
    class _InputWidgetState extends State<InputWidget> {
      final StreamController<String> _controller = StreamController<String>();
    
      void _onTextChanged(String text) {
        _controller.sink.add(text);
      }
    
      @override
      void dispose() {
        _controller.close();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              onChanged: _onTextChanged,
              decoration: InputDecoration(
                hintText: 'Type something...',
              ),
            ),
            StreamBuilder<String>(
              stream: _controller.stream,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text('Input: ${snapshot.data}');
                } else {
                  return Text('Input:');
                }
              },
            ),
          ],
        );
      }
    }
    

总结

Flutter中的Stream提供了一种处理异步事件流的高效方式。通过StreamStreamBuilder,可以在Flutter应用中处理和展示动态数据。无论是处理网络请求、用户输入还是传感器数据,Stream都提供了灵活而强大的工具。掌握Stream的使用,可以显著提升Flutter应用的响应速度和用户体验。

4o

请详细全面的讲解一下flutter中的stream

ChatGPT

Flutter中的Stream是用于处理异步事件流的重要工具,类似于RxJava中的Observable。它们可以按时间顺序接收异步事件,可以是单个或多个值。Stream特别适合用于处理网络请求、用户输入、传感器数据等连续的数据更新。以下是对Flutter中Stream的详细全面讲解。

1. 基础概念

  • Stream: 表示一个可以接收异步事件的数据源,能够生成一个或多个值。
  • StreamController: 用于控制Stream,可以向其添加事件、错误以及关闭它。
  • StreamSubscription: 表示对Stream的监听,可以用来取消订阅。
  • Sink: 用于向Stream添加数据、错误以及关闭。

2. Stream类型

  • 单订阅Stream (Single-subscription Stream) : 只能被一个监听器监听,例如Stream.periodic
  • 广播Stream (Broadcast Stream) : 可以被多个监听器同时监听,例如StreamController.broadcast()

3. 创建Stream

使用StreamController

StreamController用于创建自定义的Stream,它可以添加事件、错误以及关闭流。

dart
复制代码
import 'dart:async';

void main() {
  final controller = StreamController<int>();

  // 获取Stream
  final stream = controller.stream;

  // 监听Stream
  stream.listen((data) {
    print('Received data: $data');
  });

  // 添加数据到Stream
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);

  // 关闭Stream
  controller.close();
}

使用Stream.fromIterable

从Iterable创建一个Stream。

dart
复制代码
void main() {
  final stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  stream.listen((data) {
    print('Received data: $data');
  });
}

使用Stream.periodic

按周期生成数据的Stream。

dart
复制代码
void main() {
  final stream = Stream.periodic(Duration(seconds: 1), (count) => count);

  stream.listen((data) {
    print('Received data: $data');
  });
}

4. 监听Stream

使用listen

监听Stream中的数据、错误和完成事件。

dart
复制代码
void main() {
  final stream = Stream.fromIterable([1, 2, 3]);

  stream.listen(
    (data) {
      print('Data: $data');
    },
    onError: (error) {
      print('Error: $error');
    },
    onDone: () {
      print('Done');
    },
  );
}

5. 使用StreamBuilder

StreamBuilder是Flutter中用于监听Stream并根据数据变化更新UI的Widget。

dart
复制代码
import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('StreamBuilder Example')),
        body: Center(
          child: CounterWidget(),
        ),
      ),
    );
  }
}

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  final StreamController<int> _controller = StreamController<int>();
  int _counter = 0;

  void _incrementCounter() {
    _counter++;
    _controller.sink.add(_counter);
  }

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

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        StreamBuilder<int>(
          stream: _controller.stream,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Text('Counter: ${snapshot.data}');
            } else {
              return Text('Counter: 0');
            }
          },
        ),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('Increment Counter'),
        ),
      ],
    );
  }
}

6. 转换Stream

使用map, where等方法

对Stream的数据进行转换和过滤。

dart
复制代码
void main() {
  final stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  final transformedStream = stream.where((data) => data % 2 == 0).map((data) => 'Number $data');

  transformedStream.listen((data) {
    print(data); // 输出: Number 2, Number 4
  });
}

7. Broadcast Streams

允许多个监听器同时监听一个Stream。

dart
复制代码
void main() {
  final controller = StreamController<int>.broadcast();

  controller.stream.listen((data) => print('Listener 1: $data'));
  controller.stream.listen((data) => print('Listener 2: $data'));

  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);

  controller.close();
}

8. Combining Streams

使用StreamZip等方法组合多个Stream的数据。

dart
复制代码
import 'package:async/async.dart';

void main() {
  final stream1 = Stream.fromIterable([1, 2, 3]);
  final stream2 = Stream.fromIterable(['A', 'B', 'C']);

  final combinedStream = StreamZip([stream1, stream2]);

  combinedStream.listen((data) {
    print('Combined data: $data'); // 输出: [1, A], [2, B], [3, C]
  });
}

9. 使用场景

网络请求

在Flutter应用中,可以使用Stream处理网络请求的结果。例如,使用Stream来监听网络数据流,并通过StreamBuilder更新UI。

dart
复制代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class DataFetcher {
  final StreamController<String> _controller = StreamController<String>();

  Stream<String> get stream => _controller.stream;

  Future<void> fetchData() async {
    final response = await http.get(Uri.parse('https://api.example.com/data'));
    if (response.statusCode == 200) {
      _controller.sink.add(response.body);
    } else {
      _controller.sink.addError('Failed to fetch data');
    }
  }

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Stream Network Request Example')),
        body: Center(
          child: DataWidget(),
        ),
      ),
    );
  }
}

class DataWidget extends StatefulWidget {
  @override
  _DataWidgetState createState() => _DataWidgetState();
}

class _DataWidgetState extends State<DataWidget> {
  final DataFetcher _dataFetcher = DataFetcher();

  @override
  void initState() {
    super.initState();
    _dataFetcher.fetchData();
  }

  @override
  void dispose() {
    _dataFetcher.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<String>(
      stream: _dataFetcher.stream,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else if (snapshot.hasData) {
          return Text('Data: ${snapshot.data}');
        } else {
          return Text('No data');
        }
      },
    );
  }
}

用户输入事件

可以使用Stream来处理用户输入事件,如文本框的输入变化。

dart
复制代码
import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Stream Input Example')),
        body: Center(
          child: InputWidget(),
        ),
      ),
    );
  }
}

class InputWidget extends StatefulWidget {
  @override
  _InputWidgetState createState() => _InputWidgetState();
}

class _InputWidgetState extends State<InputWidget> {
  final StreamController<String> _controller = StreamController<String>();

  void _onTextChanged(String text) {
    _controller.sink.add(text);
  }

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

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        TextField(
          onChanged: _onTextChanged,
          decoration: InputDecoration(
            hintText: 'Type something...',
          ),
        ),
        StreamBuilder<String>(
          stream: _controller.stream,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Text('Input: ${snapshot.data}');
            } else {
              return Text('Input:');
            }
          },
        ),
      ],
    );
  }
}

总结

Flutter中的Stream提供了一种处理异步事件流的高效方式。通过StreamStreamBuilder,可以在Flutter应用中处理和展示动态数据。无论是处理网络请求、用户输入还是传感器数据,Stream都提供了灵活而强大的工具。掌握Stream的使用,可以显著提升Flutter应用的响应速度和用户体验。

转载自:https://juejin.cn/post/7380730718295392266
评论
请登录