簡體   English   中英

Flutter:將兩個 Stream 流式傳輸到一個屏幕中?

[英]Flutter : stream two Streams into a single screen?

我有兩個流從兩個不同的 api 中獲取。

Stream<Month> get monthOutStream => monthOutController.stream;
Stream<MySchedule> get resultOutStream => resultController.stream;

我在應用程序的兩種不同狀態下獲取這些數據,即開始時的結果和來自用戶的某些事件后的幾個月。

MyScheduleBloc(){
  initialData();
}

Future initialData() async {
  MySchedule mySchedule = await myScheduleViewModel.importMySchedule(now.id);
  resultController.add(mySchedule);
}

我的屏幕有一個流構建器

Widget build(BuildContext context) {
final webCalenderBloc = WebCalenderBloc();
return StreamBuilder(
  stream: webCalenderBloc.resultOutStream,
  builder: (BuildContext context , snapdata){
    if(!snapdata.hasData){
      return Center(
        child: CircularProgressIndicator(),
      );
    }
    return body(snapdata.data);
   },
 );
}

由於主要的小部件構建方法將帶有 resultoutstream 的 StreamBuilder 小部件作為流。我在哪里獲取另一個流月outStream。 我可以在流中獲取流嗎? 在處理兩個流時我是否遺漏了任何東西。我不想從monthoutstream 構建任何小部件,但想檢查其中的數據。

如果需要,您可以嵌套StreamBuilder 沒有什么可以阻止您執行以下操作:

StreamBuilder(
  stream: stream1,
  builder: (context, snapshot1) {
    return StreamBuilder(
      stream: stream2,
      builder: (context, snapshot2) {
        // do some stuff with both streams here
      },
    );
  },
)

如果這對您有意義,另一種解決方案是:流被設計為可合並/轉換。 您可以制作第三個流,它是后面兩個流的合並。

理想情況下,對於復雜的流操作,您需要使用rxdart ,因為它提供了一些有用的轉換器。

使用 rxdart,兩個Observable (它們是Stream的子類)的融合如下:

Observable<bool> stream1;
Observable<String> stream2;

final fusion = stream1.withLatestFrom(stream2, (foo, bar) {
  return MyClass(foo: foo, bar: bar);
});
Observable.combineLatest2(
        aStream,
        bStream,
        (a, b, c) =>
        a != '' && b != '');

combineLatestN 返回一個組合流

我正在使用一種 BLoC,我在其中廣播了Stream<Null> ,當某些事情發生變化時,它只會通知聽眾。 有點像 Qt 的信號和插槽。 無論如何,對於我想聽不止一個流的情況,我做了這門課。 它基本上StreamBuilder但你可以收聽多個流,它會丟棄流中的任何數據。

import 'dart:async';

import 'package:flutter/widgets.dart';

typedef MultiStreamWidgetBuilder<T> = Widget Function(BuildContext context);

// A widget that basically re-calls its builder whenever any of the streams
// has an event.
class MultiStreamBuilder extends StatefulWidget {
  const MultiStreamBuilder({
    required this.streams,
    required this.builder,
    Key? key,
  }) : super(key: key);

  final List<Stream<dynamic>> streams;
  final MultiStreamWidgetBuilder builder;

  Widget build(BuildContext context) => builder(context);

  @override
  State<MultiStreamBuilder> createState() => _MultiStreamBuilderState();
}

class _MultiStreamBuilderState extends State<MultiStreamBuilder> {
  final List<StreamSubscription<dynamic>> _subscriptions = [];

  @override
  void initState() {
    super.initState();
    _subscribe();
  }

  @override
  void didUpdateWidget(MultiStreamBuilder oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.streams != widget.streams) {
      // Unsubscribe from all the removed streams and subscribe to all the added ones.
      // Just unsubscribe all and then resubscribe. In theory we could only
      // unsubscribe from the removed streams and subscribe from the added streams
      // but then we'd have to keep the set of streams we're subscribed to too.
      // This should happen infrequently enough that I don't think it matters.
      _unsubscribe();
      _subscribe();
    }
  }

  @override
  Widget build(BuildContext context) => widget.build(context);

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

  void _subscribe() {
    for (final s in widget.streams) {
      final subscription = s.listen(
        (dynamic data) {
          setState(() {});
        },
        onError: (Object error, StackTrace stackTrace) {
          setState(() {});
        },
        onDone: () {
          setState(() {});
        },
      );
      _subscriptions.add(subscription);
    }
  }

  void _unsubscribe() {
    for (final s in _subscriptions) {
      s.cancel();
    }
    _subscriptions.clear();
  }
}

示例使用:

class AppWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiStreamBuilder(
      streams: [appState.repoListChanged, appState.selectedRepoChanged],
      builder: _buildMain,
    );
  }

  Widget _buildMain(BuildContext context) {
    return Scaffold(
      body: Row(
...

我只是寫了它,所以我沒有測試它。 我認為理論上你可以制作一個給你狀態的東西,雖然我不確定 Dart 的類型系統是否足夠先進,可以讓你在不依賴dynamic的情況下做到這一點。

好吧,就我而言,如果它們屬於同一類型,我更喜歡將多個流合並為一個。 所以你可以使用:

import 'package:async/async.dart' show StreamGroup;
...
StreamGroup.merge([stream1,stream2]);

讓我們試試Rx.merge([stream1, stream2, ....])

multiple_stream_builder包:

Widget build(BuildContext context) {
  return StreamBuilder3<int, int, int>(
    streams: Tuple3(stream1, stream2, stream3),
    initialData: Tuple3(0, 0, 0),
    builder: (context, snapshots) {
      return Text(
        'stream1: ${snapshots.item1.data} - stream2: ${snapshots.item2.data} - stream3: ${snapshots.item3.data}',
      );
    },
  );
}

multi_stream_builder包:

Widget build(BuildContext context) {
  return MultiStreamBuilder(
    streams: [stream1, stream2],
    builder: (context, dataList) {
      final stream1Value = dataList[0];
      final stream2Value = dataList[1];
      return Text('$stream1Value, $stream2Value');
    },
  );
}

錯誤:顯示用於空值的空檢查運算符。 然后我把它放在 try{}catch(e){} 塊下 & 兩個流都工作正常.. 檢查圖片在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM