Flutter&Dart-异步编程Future、Stream极速入门

简介: Flutter&Dart-异步编程Future、Stream极速入门


Dart是单线程模型,我们写的代码都运行在同一个线程中。如果做了耗时操作,会使应用程序阻塞。Dart中使用Future和Stream编写异步任务。

Future

Future是一个不会马上完成的计算过程,说的通俗一点就是一个异步执行过程,需要配合async和await一起使用。不会阻塞在此之后的代码,等待计算完成后才会返回结果。

类似于JavaScript中的Promiseasyncawait

用法

void main()  {
  requestApi();
  doSomething1();
  doSomething2();
}

doSomething1() {
  print("doSomething1");
}

doSomething2() {
  print("doSomething2");
}

/// 异步请求数据
Future requestApi() async {
  ....
  return 
}

由于requestApi() 是个异步函数,程序运行后,不会等待函数执行完成,下面的代码也会立即开始执行。

等待返回结果

如果想在异步函数返回结果后再做其他操作,可以使用then()方法来监听。

void main()  {
  requestApi().then((value) {
    /// 结果返回,开始处理
    showApiData(value);
  });
  print("程序开始运行...");
}

............
  
showApiData(dynamic value){
  print("展示获取的数据: $value");
}

FutureBuilder

const FutureBuilder({
    Key? key,
    this.future,
    this.initialData,
    required this.builder,
})


FutureBuilder会基于传入的future的返回结果来构建Widget。

使用示例

一般用于网络请求后更新UI。

class FutureBuilderDemo extends StatefulWidget {
  const FutureBuilderDemo({Key key}) : super(key: key);

  @override
  _FutureBuilderDemoState createState() => _FutureBuilderDemoState();
}

class _FutureBuilderDemoState extends State<FutureBuilderDemo> {
  Future<String> futureData;

  @override
  void initState() {
    super.initState();
    /// ui初始化时开始网络请求数据
    futureData = getData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('FutureBuilder 测试'),
      ),
      body: Container(
        child: Center(
          child: FutureBuilder<String>(
              future: futureData,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  return Text("获取的数据==${snapshot.data}");
                } else if (snapshot.hasError) {
                  return Icon(Icons.error_outline);
                } else {
                  return CircularProgressIndicator();
                }
              }),
        ),
      ),
    );
  }

  Future<String> getData() async {
    /// 模拟网络请求,等待5秒返回结果
    await Future.delayed(Duration(seconds: 5));

    /// 返回一个错误
    // return Future.error("error");
    /// 返回一个成功的结果
    return "Hello,world";
  }
}


Stream

Stream是一系列异步事件的序列,相当于一个异步的跌代器(Iterable)。不同于Future只是一个事件执行过程,Stream可以发送执行多个事件。使用场景不同。

用法

创建方式有2种,一个是单订阅的Stream,一种是能多订阅的流,也就是可以广播。

订阅后(listen)会返回一个StreamSubscription,就是一个观察者。

2种方式的构造方法都有一个可选参数sync,默认为false。

..........
   bool sync = false}) {
return sync
        ? _SyncStreamController<T>(....)
        : _AsyncStreamController<T>(...);

通过源码可以看出,sync为false创建的是一个异步事件StreamController, sync为true时创建的是一个同步StreamController。因为大部分场景下使用Stream都是为了异步,所以我们直接不传入即可。

单订阅

/// 直接使用构造函数
StreamController<String> _controller = StreamController();
StreamSubscription subscription = _controller.stream.listen((event) {
    print("subscription 接收到 $event");
});

广播订阅

void main() {
  /// 使用工厂方法构造可广播的Controller
  StreamController _controller = StreamController.broadcast();

  /// 使用多个观察者订阅同一个Stream.
  StreamSubscription subscription1 =
      _controller.stream.listen((event) => print("sub1 接收到 $event"));
  StreamSubscription subscription2 =
      _controller.stream.listen((event) => print("sub2 接收到 $event"));
  StreamSubscription subscription3 =
      _controller.stream.listen((event) => print("sub3 接收到 $event"));

  /// 发送事件后,所有已订阅的观察者的都能接收到事件。
  _controller.add("Hello");
}


运行多次,打印结果都如下不变:

sub1 接收到 Hello
sub2 接收到 Hello
sub3 接收到 Hello

Process finished with exit code 0

结论:

事件订阅(listen)的越早,接收到事件的优先级越高。

释放资源

使用完事件后或者在Flutter中Widget关闭时,记得也同时关闭Stream。

_controller.stream.listen((event) {}, onDone: () => print("收到onDone事件"));

_controller.close();
subscription.cancel();

关闭后会自动触发onDone回调方法。

StreamBuilder

在界面中,一般使用StreamBuilder来来配合Stream使用。可以实现多状态界面。

使用示例

/// 定义3种ui状态
enum UIState { type_1, type_2, type_3 }

class StreamBuilderDemo extends StatefulWidget {
  const StreamBuilderDemo({Key key}) : super(key: key);

  @override
  _StreamBuilderDemoState createState() => _StreamBuilderDemoState();
}

class _StreamBuilderDemoState extends State<StreamBuilderDemo> {
  StreamController<UIState> _controller;

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

    /// 初始化controller
    _controller = StreamController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('StreamBuilder测试'),
      ),
      body: Container(
        // height: double.infinity,
        child: Center(
          child: StreamBuilder<UIState>(

              /// 传入stream
              stream: _controller.stream,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  /// hasData代表有接收到事件
                  var data = snapshot.data;
                  Widget widget;

                  ///根据返回不回的类型,展示不同的图片
                  switch (data) {
                    case UIState.type_1:
                      widget = Icon(Icons.timer, size: 100);
                      break;
                    case UIState.type_2:
                      widget = Icon(Icons.done, size: 100);
                      break;
                    case UIState.type_3:
                      widget = Icon(Icons.ac_unit, size: 100);
                      break;
                  }
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      widget,
                      Text("$data"),
                    ],
                  );
                } else if (snapshot.hasError) {
                  /// 接收到错误事件
                  return Icon(Icons.error_outline_rounded, size: 100);
                } else {
                  /// 什么都没有,代表没还有接收到事件
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      CircularProgressIndicator(),
                      Text("初始化中,还没接收到收到状态"),
                    ],
                  );
                }
              }),
        ),
      ),
      floatingActionButton: FloatingActionButton(
          onPressed: () => generateState(), child: Icon(Icons.add)),
    );
  }

  /// 随机生成不同的状态,发送事件
  generateState() {
    var randomIndex = Random().nextInt(UIState.values.length);
    _controller.add(UIState.values[randomIndex]);
  }

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

    /// 回收资源
    _controller.close();
  }
}


相关文章
|
8天前
|
Dart
如何在 Flutter 项目中使用 Dart 语言?
如何在 Flutter 项目中使用 Dart 语言?
108 58
|
4天前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
22 7
|
2月前
|
Dart JavaScript 前端开发
Dart或Flutter中解决异常-type ‘int‘ is not a subtype of type ‘double‘
Dart或Flutter中解决异常-type ‘int‘ is not a subtype of type ‘double‘
77 4
|
2月前
|
Dart 开发工具 Android开发
Android Studio导入Flutter项目提示Dart SDK is not configured
Android Studio导入Flutter项目提示Dart SDK is not configured
93 4
|
2月前
|
Kubernetes Cloud Native 搜索推荐
探索云原生技术:Kubernetes入门与实践打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第31天】云原生技术正改变着应用开发和部署的方式。本文将带你了解云原生的基石——Kubernetes,通过实际的代码示例,从安装到部署一个简单的应用,让你迅速掌握Kubernetes的核心概念和操作方法。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你进入云原生世界的桥梁。
|
2月前
|
Dart 开发工具
消除Flutter doctor的警告Warning: `dart` on your path resolves to xxx/bin/dart
消除Flutter doctor的警告Warning: `dart` on your path resolves to xxx/bin/dart
32 0
|
4月前
|
开发框架 前端开发 测试技术
Flutter开发常见问题解答
Flutter开发常见问题解答
|
5月前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
23天前
|
JSON Dart Java
flutter开发多端平台应用的探索
flutter开发多端平台应用的探索
27 6
|
23天前
|
JSON Dart Java
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
下一篇
无影云桌面