Flutter| 事件循环,Fluture(上)

简介: Flutter| 事件循环,Fluture(上)

在 Dart 中,没有多线程的概念,所谓的异步操作全部都是在一个线程里面执行的, 并且不会造成卡顿的原因就是事件循环(Event Loop),


如下图所示,在程序的运行过程中,会有两个事件


image.png


补充上图:Micortask Queue 为空 才会执行 EventQueue ,EventQueue 为空时程序结束,实际上,事件循环从启动的之后会一直执行。


在程序执行过程中,如果有异步操作,这个操作就会添加到队列中,当发现队列不为空时,就会然后不断的从队列中取出事件在执行


Microtask Queue


一个顶级的队列,只要这个队列里面不是空的,就一定会执行该队列中的任务,


scheduleMicrotask(() {
  print("Hello Flutter");
});


Future.microtask() //内部调用的也是上面的函数


但是需要注意的是,一般的实战中,我们不会手动给这个队列里面添加事件,该队列一般都是由 Dart 自己来处理的。


Event Queue


普通的事件队列,比 Microtask Queue 低了一个等级,在 Microtask Queue 中没有任务的时候才会执行该队列中的任务


需要异步操作的代码都会放在 EventQueue 中执行,例如:


Future((){
  print('这里会被放在 EventQueu 中执行');
})
Future.delayed(Duration(seconds: 1), () {
  print('这里会被放在 EventQueu 中执行');
});


直接执行的代码


Future.sync(() => print('Hello'));
Future.value(() => print('world'));
xxx.then()


Future


Flutter 相当于是一个盒子,内部的代码最终会交给 EventQueue 来执行,Future 的状态大致可分为三种,如下:


Future(() {
    print('未完成状态');
})
.then((value) => print('已完成状态'))
.catchError((value) => print('异常状态'));


我们程序中的大部分异步操作都是围绕着这三种状态进行的。


Future 常用的函数


Future.error()
Future(() {
  return Future.error(Exception());
}).then((value) => print('已完成状态')).catchError((value) => print('异常状态'));


创建一个以异常结束的 Future,上面代码最终会执行到 catchError 中。


Future.whenComplete()


类似于 try catch 后面的 finnaly,无论成功和失败,最终都会执行到这里


Future.them 链式调用


//在 them 中可以接继续返回值,该值会在下一个链式的 then 调用中拿到返回的结果
getNetData().then((value) {
  //支持成功到此处
  print(value);
  return "data1";
}).then((value) {
  print(value);
  return "data2";
}).then((value) {
  print(value);
}).catchError((error) {
  //执行失败到此处
  print(error);
}).whenComplete(() => print("完成"));


Future.wait()


如果要等到多个异步任务都结束之后再进行一些操作,可以使用 Future.wait


Future.wait([getNetData(), getNetData(), getNetData()]).then((value) {
  value.forEach((element) {
    print(element);
  });
});


Future.delayed()


延时指定的时间后在执行


Future.delayed(Duration(seconds: 3), () {
    return "3秒后的信息";
  }).then((value) {
    print(value);
  });


async,await


async:用来表示函数是异步的,定义的函数会返回一个 Future 对象,可以使用 then 添加回调函数


await :后面是一个 Future,表示等待改异步任务的完成,异步完成之后才会继续往下走,await 必须出现在 async 的内部


void main() {
  print("start ----------->");
  getNetData().then((value) => print(value));
  print("end -------------->");
}
// async 会将返回的结果封装为 Future 类型
getNetData() async {
  var result1 = await Future.delayed(Duration(seconds: 3), () {
    return "网络数据1";
  });
  var result2 = await Future.delayed(Duration(seconds: 3), () {
    return "网络数据2";
  });
  return result1 + "-----" + result2;
}


FutureBuilder


监听一个 Future,以 Future 的状态来进行 setState


class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: Future.value(10),
        builder: (BuildContext context, AsyncSnapshot<dynamic> snap) {
          return DemoWidget()
        });
  }
}


构造


future :接受一个 future,当 future 的值发生变化之后,就会自动调用下面的 build 函数,


initialData:初始值,在 future 没完成的时候可以暂时使用该值,该值会放在 AsyncSnapshot 的 data 中,在 future 未完成的时候可以使用该值。在 future 出错的时候,该值会被 AsyncSnapshot 从 data 中删掉


builder:返回一个 Widget


AsyncSnapshot 用来保存 future 最近的状态,这个状态只有两个情况,一种是有数据 data,一种是错误状态 error。 AsyncSnapshot 中还有 ConnectionState 状态,分别表示的是 none :没有传递 future,waiting:等待中,active:TODO ,done :表示已经完成


FutureBuilder 的作用就是根据 future 的状态来判断当前页面需要显示哪些 widiget,例如 future 在等待的时候显示加载框,完成之后显示内容等。


需要注意的一点是当状态为 done 是,可能会有两种情况,一种是 future 成功了,另一种是 future 失败了,内部有异常,这个时候就不应该获取 data,而是判断 snap.hasData 来进行判断。


示例


class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: Future.value(10),
        builder: (BuildContext context, AsyncSnapshot<dynamic> snap) {
          if (snap.connectionState == ConnectionState.waiting) {
            return CircularProgressIndicator();
          }
          if (snap.connectionState == ConnectionState.done) {
            if (snap.hasData) {
              return DemoWidget();
            } else {
              return Text(snap.error);
            }
          }
          throw "should not happen";
        });
  }
}
//在精简一些
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: Future.value(10),
        builder: (BuildContext context, AsyncSnapshot<dynamic> snap) {
          //如果有数据  
          if (snap.hasData) {
            return DemoWidget();
          }
           //如果发生错误
          if (snap.hasError) {
            return Text(snap.error);
          }
          // 等待中,显示加载框
          return CircularProgressIndicator();
        });
  }
}


源码浅析


/// State for [FutureBuilder].
class _FutureBuilderState<T> extends State<FutureBuilder<T>> {
  //....
  @override
  void initState() {
      //如果没有初始值,则先设置Wie none 状态,如果有,则传入初始值 
        _snapshot = widget.initialData == null
        ? AsyncSnapshot<T>.nothing()
        : AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData as T);
    _subscribe();
  }
  @override
  void didUpdateWidget(FutureBuilder<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.future != widget.future) {
     //....
      _subscribe();
    }
  }
  void _subscribe() {
    if (widget.future != null) {
      final Object callbackIdentity = Object();
      _activeCallbackIdentity = callbackIdentity;
      widget.future!.then<void>((T data) {
        if (_activeCallbackIdentity == callbackIdentity) {
          //任务执行完成,将数据传给 _snapshot ,并刷新
          setState(() {
            _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data);
          });
        }
      }, onError: (Object error, StackTrace stackTrace) {
        if (_activeCallbackIdentity == callbackIdentity) {
          setState(() {
              //出现错误
            _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error, stackTrace);
          });
        }
        assert(() {
           //判断调试状态 
          if(FutureBuilder.debugRethrowError) {
            Future<Object>.error(error, stackTrace);
          }
          return true;
        }());
      });
       //没有完成则是等待状态
      _snapshot = _snapshot.inState(ConnectionState.waiting);
    }
  }


源码其实很简单,仔细看一下就知道整个流程了


StreamBuilder


介绍


上面的 FutureBuilder 只能给我们一个值,而 StreamBuildder 可以给我们一连串的值 ,例如:


final stream = Stream.periodic(Duration(seconds: 1), (count) => count++);
stream.listen((event) {
  print(event);
});


示例


class _MyHomePageState extends State<MyHomePage> {
  final stream = Stream.periodic(Duration(seconds: 1), (count) => count++);
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      color: Colors.white,
      child: DefaultTextStyle(
        style: TextStyle(fontSize: 30, color: Colors.black),
        child: StreamBuilder(
            stream: stream,
            builder: (BuildContext context, AsyncSnapshot<dynamic> snap) {
              switch (snap.connectionState) {
                case ConnectionState.none:
                  return Text("NONE:没有数据流");
                  break;
                case ConnectionState.waiting:
                  return Text("WAITING:等待数据流");
                  break;
                case ConnectionState.active:
                  if (snap.hasData) {
                    return Text(snap.data.toString());
                  }
                  if (snap.hasError) {
                    return Text(snap.error.toString());
                  }
                  break;
                case ConnectionState.done:
                  return Text("DONE:数据流已关闭");
                  break;
              }
              return CircularProgressIndicator();
            }),
      ),
    );
  }
}


其实和 FutureBuilder 差不多,只不过多了一个 active 状态,这个状态在上面没有说是因为用不到**,在这里的意思指的就是数据流是否为活跃的**,如果是活跃的,则就可以获取他的值了


创建方式及常用的函数


使用 Stream.periodic 的方式来创建一个数据流,如上面的示例所示


读取文件的方式


File("").openRead().listen((event) { 
})


将读取的文件信息以数据流的方式转给我们


使用 StreamController


final controller = StreamController();
controller.stream.listen((event) {
  print('$event');
});
controller.sink.add(12);
controller.sink.add(13);
controller.sink.add(14);
controller.sink.add(15);
controller.sink.addError("Error");
//关闭后则不能进行任何添加操作
controller.close();


相关文章
|
Dart Linux API
Flutter 上使用 C/C++ 代码(上)
Flutter 上使用 C/C++ 代码(上)
2627 0
Flutter 上使用 C/C++ 代码(上)
|
1月前
|
Dart 前端开发 API
【Flutter前端技术开发专栏】Flutter中的异步编程与Future/async/await
【4月更文挑战第30天】本文探讨了Flutter中的异步编程,强调其在提高应用响应性和性能上的重要性。Flutter使用`Future`对象表示异步操作的结果,通过`.then()`和`.catchError()`处理异步任务。此外,Dart的`async/await`关键字简化了异步代码,使其更易读。理解并运用这些概念对于开发高效的Flutter应用至关重要。
【Flutter前端技术开发专栏】Flutter中的异步编程与Future/async/await
|
11月前
|
XML JSON Dart
《深入浅出Dart》Flutter网络请求
Flutter网络请求 网络请求是移动应用开发中常见的任务之一,Flutter提供了强大且易于使用的网络请求库,使得我们能够轻松地与服务器进行通信。我们将探讨不同类型的网络请求、错误处理、异步操作以及如何解析和处理响应数据。
162 0
|
Dart 前端开发 JavaScript
Flutter(二十二)——异步编程
Flutter(二十二)——异步编程
249 2
Flutter(二十二)——异步编程
|
Dart JavaScript
Flutter | 事件处理(下)
Flutter | 事件处理(下)
Flutter | 事件处理(下)
|
API 容器
Flutter | 事件处理(上)
Flutter | 事件处理(上)
Flutter | 事件处理(上)
啥?Flutter也能整3D了吗?我靠,竟然是这样的操作👀
当我看了这样一个节目之后,我发现,复杂的ui竟然这么简单就可以实现了!当时我就用Flutter整了这么个3D效果,快来围观!!
|
前端开发 JavaScript
Flutter事件监听
在大前端的开发中,必然存在各种各样和用户交互的情况:比如手指点击、手指滑动、双击、长按等等。
174 0
Flutter事件监听
|
Dart Java API
Flutter 异步编程原理(中)
Flutter 异步编程原理(中)
203 0
Flutter 异步编程原理(中)
|
消息中间件 Dart API
Flutter 异步编程原理(上)
Flutter 异步编程原理(上)
412 0
Flutter 异步编程原理(上)