Flutter Advanced - Future、FutureBuilder、StreamBuilderの詳細解説

1. タイムループイベントループの仕組み

プログラムがスタックする理由は、UI インターフェイスを更新して画面を更新する時間がないためです。

ラグには主に 2 つのタイプがあります。

1. CPU が大量の計算でビジー状態になる

2. 待機、サーバーの応答を待機、ユーザーの入力を待機、ファイルが読み取られるのを待機...など。

マルチスレッド メカニズムでは、何かを待機する必要があるたびに、それを保護するために新しいスレッドが開かれ、UI の更新を担当するメイン スレッドがハングしたり、スタックしたりすることはありません。

しかし、Dart では、各スレッドは Isolate にカプセル化され、各 Isolate は分離されて分離され、互いにメモリを共有せず、メッセージを送信することで相互に通信します。

直接実行する マイクロタスク イベント

Future.sync()

スケジュールマイクロタスク()

未来()

Future.value()

Future.microtask()

Future.遅延()

_。それから() _completed.then()

二、FutureBuilder 

渡された将来の値の変化を監視してインターフェイスを更新します (setState を使用せず)

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(''),
      ),
      body: FutureBuilder(
        initialData: "haha",
          future:
              Future.delayed(const Duration(seconds: 2), () => throw ('error')),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return const Icon(Icons.error);
            }
            if (snapshot.hasData) {
              return Text("${snapshot.data}");
            }
            return const CircularProgressIndicator();
          }),
    );
  }

3. ストリームとStreamBuilder

future は 1 回だけ印刷されますが、Stream は引き続き印刷されます

 final future = Future.delayed(const Duration(seconds: 2), () => 40);
 final stream = Stream.periodic(const Duration(seconds: 1), (_) => 42);


 void test() {
    future.then((value) => print('future completed: $value'));
    stream.listen((event) {
      print("stream: $event");
    });
  }

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text(''),
        ),
        body: StreamBuilder(
            stream: stream,
            builder: (context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return const Text("none: 没有数据");
                case ConnectionState.waiting:
                  return const Text("waiting: 等待数据流");
                case ConnectionState.active:
                  if (snapshot.hasError) {
                    return Text("active: 错误${snapshot.error}");
                  } else {
                    return Text("active: 正常${snapshot.data}");
                  }
                case ConnectionState.done:
                  return const Text("active: 数据流已经关闭");
              }
            }));
  }

StreamController でストリームをより便利に管理 

final StreamController streamController = StreamController();
  
@override
  void dispose() {
    streamController.close();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    streamController.sink.add(72);
    streamController.stream.listen((event) {});
  }

  final StreamController streamController = StreamController();
  int count = 10;

  DefaultTextStyle(
                style: Theme.of(context).textTheme.headline4!,
                child: Column(children: [
                  RaisedButton(
                      child: const Text('10'),
                      onPressed: () {
                        count += 10;
                        streamController.sink.add(count);
                      }),
                  StreamBuilder(
                      stream: streamController.stream,
                      builder: (context, snapshot) {
                        switch (snapshot.connectionState) {
                          case ConnectionState.none:
                            return const Text("none: 没有数据");
                          case ConnectionState.waiting:
                            return const Text("waiting: 等待数据流");
                          case ConnectionState.active:
                            if (snapshot.hasError) {
                              return Text("active: 错误${snapshot.error}");
                            } else {
                              return Text("active: 正常${snapshot.data}");
                            }
                          case ConnectionState.done:
                            return const Text("active: 数据流已经关闭");
                        }
                      })
                ]));

 複数回監視されると、エラー streamController.stream.listen((event) {}); が報告されます。ブロードキャストになるには、最終的な StreamController streamController = StreamController.broadcast(); を使用する必要があります。

例:

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = StreamController();
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: StreamBuilder(
            stream: _controller.stream,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text("你输入了: ${snapshot.data.toString()}",
                    style: const TextStyle(
                        fontSize: 24, fontWeight: FontWeight.bold));
              }
              return const Text("等待...");
            }),
      ),
      body: Stack(children: [
        Puzzle(inputStream: _controller.stream),
        Align(
            alignment: Alignment.bottomCenter,
            child: KeyPad(controller: _controller))
      ]
      ),
    );
  }
}

class KeyPad extends StatelessWidget {
  final StreamController controller;
  const KeyPad({Key? key, required this.controller}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GridView.count(
        shrinkWrap: true,
        childAspectRatio: 2 / 1,
        crossAxisCount: 3,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
        children: List.generate(
            9,
            (index) => FlatButton(
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10)),
                color: Colors.primaries[index][200],
                onPressed: () {
                  controller.add(index + 1);
                },
                child: Text(
                  "${index + 1}",
                  style: const TextStyle(fontSize: 24),
                ))));
  }
}

class Puzzle extends StatefulWidget {
  final Stream inputStream;
  const Puzzle({Key? key, required this.inputStream}) : super(key: key);

  @override
  State<Puzzle> createState() => _PuzzleState();
}

class _PuzzleState extends State<Puzzle> with SingleTickerProviderStateMixin {
  late int a, b;
  late Color color;

  late AnimationController _controller; //显示动画

  reset() {
    a = Random().nextInt(5) + 1;
    b = Random().nextInt(5);
    color = Colors.primaries[Random().nextInt(Colors.primaries.length)];
  }

  @override
  void initState() {
    reset();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 10))
          ..forward();
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        reset();
        _controller.forward(from: 0.0);
      }
    });
    widget.inputStream.listen((input) {
      if (input == a + b) {
        _controller.forward(from: 0.0);
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: _controller,
        builder: (context, _) {
          return Positioned(
            top: 400 * _controller.value,
            left: 200 * _controller.value,
            child: Container(
              decoration: BoxDecoration(
                  color: color,
                  border: Border.all(color: Colors.black),
                  borderRadius: BorderRadius.circular(24)),
              padding: const EdgeInsets.all(5),
              child: Text(
                "$a + $b",
                style: const TextStyle(fontSize: 24),
              ),
            ),
          );
        });
  }
}

おすすめ

転載: blog.csdn.net/RreamigOfGirls/article/details/131164963