Flutter 09 Future 和 Stream

一、Future 和 Stream 是处理异步操作的两个重要概念:

Future:

Future 用于表示一个延迟操作的值或错误,即异步操作的结果。通过 Future,可以在异步操作完成后获取其结果。可以使用 async 和 await 关键字来处理 Future,使得异步操作更加直观和易于管理。

Stream:

Stream 则用于处理一系列异步数据(事件)的序列。它可以持续地产生数据,而不是单一的结果。Stream 可以用于处理事件、文件读写、状态管理等需求。使用 StreamController 可以很好的控制 Stream 的创建和数据添加。

二、Future的使用:

async 和 await。

async:用于在方法或函数声明前添加,表示该方法是一个异步方法。在异步方法中,执行顺序可以是非阻塞的,不会阻塞当前线程。

await:用于在异步方法中等待并获取异步表达式的执行结果,只能在被 async 修饰的方法中使用。

1、模拟一个异步请求数据的实现

通过async关键字声明一个异步方法,延迟2秒后返回模拟的结果String值。

Future<String> getAsyncData() async {
    setState(() {
      asyncData = "开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 2));
    return "返回:Future get async data.";
}

通过按钮点击触发模拟接口请求,获取到异步数据后更新到页面中。 

ElevatedButton(
  onPressed: () {
	getAsyncData().then((value) {
	  setState(() {
		asyncData = value;
	  });
	});
  },
  child: const Text("Future get async data.")),
Text(asyncData),

2、模拟两个异步请求并行,待全部接口请求完成后获取数据的实现

通过async关键字声明两个异步方法,分别延迟2秒和延迟3秒后,返回模拟的结果String值。

Future<String> getAsyncData2() async {
    setState(() {
      asyncTowData = "getAsyncData2开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 2));
    setState(() {
      asyncTowData = "getAsyncData2完成请求数据";
    });
    return "延迟2秒返回";
}

Future<int> getAsyncData3() async {
    setState(() {
      asyncTowData = "getAsyncData3开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 3));
    setState(() {
      asyncTowData = "getAsyncData3完成请求数据";
    });
    return 3;
}

创建第三个异步方法,将上面的两个异步方法添加到数组里面,并行执行。

// 同时执行两个异步方法并等待它们的结果
Future<List<dynamic>> getTowAsyncData() async {
    List<Future<dynamic>> futures = [getAsyncData2(), getAsyncData3()];
    List<dynamic> result = await Future.wait(futures);
    return result;
}

通过按钮点击触发模拟接口请求,获取到异步数据后更新到页面中。 

ElevatedButton(
  onPressed: () {
	getTowAsyncData().then((value) {
	  var data1 = value[0] as String;
	  var data2 = value[1] as int;
	  setState(() {
		asyncTowData = "$data1,延迟$data2秒返回";
	  });
	});
  },
  child: const Text("Future get tow async data.")),
Text(asyncTowData),

3、FutureBuilder 使用

通过FutureBuilder实现请求数据时展示加载组件,请求成功后显示数据。

Widget _init() {
    return FutureBuilder(
      future: initAsyncData(),
      builder: (context, snapshot) {
        // 等待状态显示的widget
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(
            child: CircularProgressIndicator(),
          );
          //  错误时显示的widget
        } else if (snapshot.hasError) {
          return const Text('Error');
          // 加载完成后显示的数据
        } else {
          return _widget();
        }
      },
    );
}

4、FuturePage完整代码

import 'package:flutter/material.dart';

///create by itz on 2024/8/16 14:55
///desc : 
class FuturePage extends StatefulWidget {
  const FuturePage({super.key});

  @override
  State<FuturePage> createState() => _FuturePageState();
}

class _FuturePageState extends State<FuturePage> {

  String asyncData = "";
  String asyncTowData = "";
  bool isInit = false;

  Future initAsyncData() async {
    await Future.delayed(const Duration(seconds: 2));
    isInit = true;
  }

  Future<String> getAsyncData() async {
    setState(() {
      asyncData = "开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 2));
    return "返回:Future get async data.";
  }

  Future<String> getAsyncData2() async {
    setState(() {
      asyncTowData = "getAsyncData2开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 2));
    setState(() {
      asyncTowData = "getAsyncData2完成请求数据";
    });
    return "延迟2秒返回";
  }

  Future<int> getAsyncData3() async {
    setState(() {
      asyncTowData = "getAsyncData3开始请求数据";
    });
    await Future.delayed(const Duration(seconds: 3));
    setState(() {
      asyncTowData = "getAsyncData3完成请求数据";
    });
    return 3;
  }

  // 同时执行两个异步方法并等待它们的结果
  Future<List<dynamic>> getTowAsyncData() async {
    List<Future<dynamic>> futures = [getAsyncData2(), getAsyncData3()];
    List<dynamic> result = await Future.wait(futures);
    return result;
  }

  @override
  Widget build(BuildContext context) {
    Widget w = isInit ? _widget() : _init();
    return Scaffold(
      appBar: AppBar(
        title: const Text("Future"),
      ),
      body: w,
    );
  }

  Widget _init() {
    return FutureBuilder(
      future: initAsyncData(),
      builder: (context, snapshot) {
        // 等待状态显示的widget
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(
            child: CircularProgressIndicator(),
          );
          //  错误时显示的widget
        } else if (snapshot.hasError) {
          return const Text('Error');
          // 加载完成后显示的数据
        } else {
          return _widget();
        }
      },
    );
  }

  Widget _widget() {
    return Container(
      margin: const EdgeInsets.all(16),
      child: ListView(
        children: [
          ElevatedButton(
              onPressed: () {
                getAsyncData().then((value) {
                  setState(() {
                    asyncData = value;
                  });
                });
              },
              child: const Text("Future get async data.")),
          Text(asyncData),
          const SizedBox(height: 10),
          ElevatedButton(
              onPressed: () {
                getTowAsyncData().then((value) {
                  var data1 = value[0] as String;
                  var data2 = value[1] as int;
                  setState(() {
                    asyncTowData = "$data1,延迟$data2秒返回";
                  });
                });
              },
              child: const Text("Future get tow async data.")),
          Text(asyncTowData),
        ],
      ),
    );
  }
}

三、Stream的使用

在Flutter中,Stream 是用于处理异步事件序列的概念,常见应用包括:

异步数据获取:Stream在异步数据获取方面非常有用。例如,在网络请求中,可以使用 Stream 来处理异步数据的传输和响应。通过监听 Stream,可以实时获取数据并更新应用程序的界面,实现动态数据展示的功能。

状态管理:Stream在状态管理中扮演着重要的角色。通过创建包含状态信息的 Stream,可以在应用程序中管理状态的变化。当状态发生变化时,通过 Stream 向订阅者(监听者)发送新的状态信息,从而触发相应的操作或界面更新。

事件总线:Stream可以作为事件总线,用于在应用程序中处理和传递事件。通过创建一个全局的 Stream,不同部分的应用程序可以监听并发送事件,实现模块之间的通信和交互。这种方式可以实现解耦和灵活的组件通信。

文件读写:Stream`也可以用于处理文件读写操作。例如,读取大文件时可以使用 Stream实现分块读取,提高读取效率。同样,可以通过 Stream 监听文件写入事件,实现实时监控文件变化等功能。

1、异步数据获取

1)创建StreamController 控制器,控制 Stream 的创建、数据添加 和 关闭等操作。

final StreamController _streamController = StreamController();

2)创建异步方法,模拟异步数据获取

getStreamData() async {
    for (int i = 0; i < 10; i++) {
      await Future.delayed(const Duration(seconds: 1));
      // 发送值
      _streamController.sink.add(i);
    }
    await Future.delayed(const Duration(seconds: 1));
    // 发送值
    _streamController.sink.add("done");
}

3)创建StreamBuilder用于接收流式数据

StreamBuilder(
  stream: _streamController.stream,
  builder: (context, snapshot) {
	if (snapshot.hasData) {
	  return Text('异步数据:${snapshot.data}');
	} else if (snapshot.hasError) {
	  return Text('发生错误:${snapshot.error}');
	} else {
	  return const Text('加载中...');
	}
  })

4)通过按钮点击触发模拟接口请求

ElevatedButton(
  onPressed: () {
	getStreamData();
  },
  child: const Text("stream get async data.")),

5)完整代码 

/*年轻人,只管向前看,不要管自暴自弃者的话*/

import 'dart:async';

import 'package:flutter/material.dart';

///create by itz on 2024/8/16 15:46
///desc :
class StreamPage extends StatefulWidget {
  const StreamPage({super.key});

  @override
  State<StreamPage> createState() => _StreamPageState();
}

class _StreamPageState extends State<StreamPage> {
  // 创建控制器
  final StreamController _streamController = StreamController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Stream"),
      ),
      body: _widget(),
    );
  }

  Widget _widget() {
    return Container(
      margin: const EdgeInsets.all(16),
      child: ListView(
        children: [
          ElevatedButton(
              onPressed: () {
                getStreamData();
              },
              child: const Text("stream get async data.")),
          StreamBuilder(
              stream: _streamController.stream,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text('异步数据:${snapshot.data}');
                } else if (snapshot.hasError) {
                  return Text('发生错误:${snapshot.error}');
                } else {
                  return const Text('加载中...');
                }
              })
        ],
      ),
    );
  }

  getStreamData() async {
    for (int i = 0; i < 10; i++) {
      await Future.delayed(const Duration(seconds: 1));
      // 发送值
      _streamController.sink.add(i);
    }
    await Future.delayed(const Duration(seconds: 1));
    // 发送值
    _streamController.sink.add("done");
  }
}

2、事件总线

1)创建EventBus单例类

import 'dart:async';

///create by itz on 2024/8/16 15:54
///desc :
class EventBus {
  static final EventBus _instance = EventBus._internal();

  factory EventBus() => _instance;

  EventBus._internal();

}

2)使用 broadcast() 方法创建了一个可以实时广播事件的 StreamController

final _controller = StreamController<dynamic>.broadcast();

3)创建 get stream,发送事件,关闭控制器等方法

  Stream get stream => _controller.stream;

  void fire(dynamic event) {
    _controller.sink.add(event);
  }

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

4)使用EventBus,设置EventBus事件监听

    EventBus().stream.listen((event) {
      setState(() {
        eventInfo = event;
      });
    });

5)发送EventBus事件

sendEvent(String event) {
    EventBus().fire(event);
  }

6)通过按钮点击触发发送事件

ElevatedButton(
	onPressed: () {
	  sendEvent("cat");
	},
	child: const Text("send Event.")),
Text(eventInfo),

7)完整EventBus代码

import 'dart:async';

///create by itz on 2024/8/16 15:54
///desc :
class EventBus {
  static final EventBus _instance = EventBus._internal();

  factory EventBus() => _instance;

  EventBus._internal();

  // 使用 broadcast() 方法创建了一个可以实时广播事件的 StreamController
  final _controller = StreamController<dynamic>.broadcast();

  Stream get stream => _controller.stream;

  void fire(dynamic event) {
    _controller.sink.add(event);
  }

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

8)完整EventBusPage代码

import 'package:async_test/util/EventBus.dart';
import 'package:flutter/material.dart';

///create by itz on 2024/8/16 16:01
///desc :
class EventBusPage extends StatefulWidget {
  const EventBusPage({super.key});

  @override
  State<EventBusPage> createState() => _EventBusPageState();
}

class _EventBusPageState extends State<EventBusPage> {
  String eventInfo = "";

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    EventBus().stream.listen((event) {
      setState(() {
        eventInfo = event;
      });
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    EventBus().dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("EventBus"),
      ),
      body: Container(
        margin: const EdgeInsets.all(16),
        child: ListView(
          children: [
            ElevatedButton(
                onPressed: () {
                  sendEvent("cat");
                },
                child: const Text("send Event.")),
            Text(eventInfo),
          ],
        ),
      ),
    );
  }

  sendEvent(String event) {
    EventBus().fire(event);
  }
}

Stream 适用于处理持续产生数据的异步操作,而 async/await 适用于一次性获取结果的异步操作。两者使用区别包括控制流、数据处理、使用场景和代码结构。

Provider 与 Stream 区别在于使用 Provider 时状态可以被存储起来,而 Stream 不会存储。选择使用哪种取决于需求和代码结构的复杂度。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sziitjin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值