本篇依据Flutter 3.16.4,Dart 3.2.3版别
Flutter 3.16.4 • channel stable • github.com/flutter/flu…
Framework • revision 2e9cb0aa71 (3 days ago) • 2023-12-11 14:35:13 -0700
Engine • revision 54a7145303
Tools • Dart 3.2.3 • DevTools 2.28.4
本篇为Flutter基建的第八篇文章,首要介绍FutureBuilder、StreamBuilder和经过Dio网络恳求更新UI相关的常识,都是和异步加载UI相关,下面快速进入文章的了解下吧~
Flutter基建 – 寸步不离的State**Widget
简述
FutureBuilder和StreamBuilder都是Flutter为开发者提供快速完结异步加载UI的方案,它们不同的是一个依赖的是Future另一个依赖的是Stream,一般情况下咱们运用Future就能够完结大部分的异步操作,它能够异步加载咱们需求的数据,那Stream是不是剩余的呢?并不是,Stream专门用于异步加载流的类型,比方文件的读写和网络文件的下载等等场景,所以它们各有各的特长,小伙伴们在看完这篇文章之后能够依据实际的业务需求在它们之间选择。
接下来先看看FutureBuilder的详细运用。
FutureBuilder异步
const FutureBuilder({
super.key,
required this.future,
this.initialData,
required this.builder,
});
FutureBuilder的结构函数十分简略,只有四个参数:
- future参数用于接收一个Future类型的目标,用于处理异步恳求;
- initialData参数能够界说初始值,在异步操作未完结之前能够运用此参数的值来展现页面信息;
- builder参数则是处理异步回调操作的逻辑,能够在此参数内部处理异步操作完结前后的逻辑并回来指定的Widget。
class _FutureState extends State<FutureWidgetExample> {
@override
Widget build(BuildContext context) {
return buildScaffold(
context,
Center(
child: FutureBuilder(
future: buildFuture(),
builder: (context, result) {
var state = result.connectionState;
debugPrint('future state: ${state.name}');
if (state == ConnectionState.done) {
return Text(result.data ?? "Future Error");
} else {
return const CircularProgressIndicator();
}
},
),
),
);
}
Future<String> buildFuture() async {
return Future.value('Future value');
}
}
log:
future state: waiting
future state: done

这儿咱们经过FutureBuilder创建了一个异步加载的UI,future参数传入的是buildFuture()办法,此办法内部采用了最简略的Future.value()回来了一个字符串;然后builder参数内部依据ConnectionState类型回来了两种不同的Widget,假如state为done那么就回来一个Text来展现Future的成果,假如state非done那么就展现加载loading。
由于buildFuture()办法内部是直接回来的成果,此代码会看不到加载loading,咱们能够将Future.value()改为
Future<String> buildFuture() async {
return Future.delayed(const Duration(seconds: 2), () {
return 'Future value';
});
}
这样咱们先延时2s之后再回来字符串,这样就能够很清晰的看出界面的改变。
这儿咱们再了解下ConnectionState概念,它一个有四种状况,分别为:
- none:此状况表明FutureBuilder中future参数传入的为空,当时没有异步使命在执行;
- waiting:此状况表明异步使命正在执行,还没收到最终成果;
- active:此状况在FutureBuilder中不简单理解,在后边的StreamBuilder中能够很简单的理解,它表明的是当时异步使命现已收到了回来的数据,可是异步使命并没有完毕,后边还会收到别的数据;能够用读取文件的使命来加深理解,读取文件是一个进程,从开端到完毕会一向承受文件的流,在未接收完之前ConnectionState会一向是active状况,比及整个文件都接收完结之后,active状况就会变为done状况;
- done:此状况表明的是异步使命现已完结。
上面就是ConnectionState四种状况的概括性解说,上述代码中咱们也是添加了debugPrint来输出state,大家能够执行下代码来看看整个使命的state是如何改变的,此刻state的改变是:waiting -> done,由于咱们buildFuture是一个一次性的使命,所以中途不会出现active状况,active状况咱们会在StreamBuilder种介绍。
StreamBuilder异步
const StreamBuilder({
super.key,
this.initialData,
required super.stream,
required this.builder,
});
对比FutureBuilder的结构函数来看,StreamBuilder和它的差异就在于stream参数,其余的基本上是共同的,这儿就不过多解析了,直接进入实战环节。
class _StreamState extends State<StreamWidgetExample> {
@override
Widget build(BuildContext context) {
return buildScaffold(
context,
Center(
child: StreamBuilder(
initialData: "init stream data",
stream: buildStream(),
builder: (context, result) {
var connectionState = result.connectionState;
debugPrint('stream state: ${connectionState.name}');
if (connectionState == ConnectionState.done) {
return Text(result.data ?? 'Stream error');
} else {
return Text(result.data ?? 'init data');
}
},
),
),
);
}
Stream<String> buildStream() {
return Stream.periodic(const Duration(seconds: 1), (i) {
return "$i";
});
}
}
运用办法也是类似于FutureBuilder,不过这儿咱们多传入了一个initialData参数,然后在buildStream()办法里运用的是Stream.periodic()办法回来的Stream目标,periodic表明的是周期性使命,这儿界说的每隔1s回来阶段性的成果。运用periodic()办法的目的是为了能够清晰的展现initialData的效果。
经过debugPrint的日志能够看出,ConnectionState的状况在第一次周期使命完毕之前一向是waiting状况,后边都是active状况,并且这儿不会有done状况,由于咱们Stream.periodic是一向在跑的,实际开发中读取文件或许下载文件等操作仍是会有done状况的。
这儿留意的是在builder参数内部咱们非done状况是展现的是Text,Text的内容为result.data,试想一下周期使命的前1s还未收到阶段性成果,此刻会Text的内容会展现啥呢?下面来看下详细运行的效果图。
经过上面的GIF能够看出,在前1s的时候Text展现的是initialData值,然后每隔1s显示的内容从0顺次+1。
经过上面的介绍,FutureBuilder和StreamBuilder相关常识就梳理完结了,异步加载UI的内容在日常开发中仍是运用的蛮多的,小伙伴们假如是第一次触摸可能会感觉到有点繁琐,可是用多了就会逐渐娴熟起来,最终咱们经过FutureBuilder的办法加载接口数据再次了解一下,这种办法也是实际开发触摸的比较多的~
Dio加载接口数据
dio 是一个强壮的 HTTP 网络恳求库,支持全局装备、Restful API、FormData、拦截器、 恳求取消、Cookie 办理、文件上传/下载、超时、自界说适配器、转换器等。
以上是Dio官方的介绍,详细运用能够去阅览Dio的官方文档
引进Dio库
在运用Dio之前,咱们先在工程的pubspec.yaml文件中引进Dio库
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
dio:
然后再Android模块的Manifest文件中添加网络权限,否则接口恳求就不会成功的哈~
界说接口数据类
接口恳求咱们运用的是WanAndroid开放的Api,日常调试接口的神级接口,官方地址为:WanAndroid
以主页数据接口为例,现在浏览器中恳求一次,拿到接口的回来数据,然后在Json To Dart网页中生成实体类。这儿生成的实体类代码有点多,就不在文章中贴出详细代码了。
接口恳求
Future<Response> fetchArticle() {
Dio dio = Dio();
return dio.get("https://www.wanandroid.com/article/list/0/json");
}
采用Dio办法完结接口恳求十分简略,只需求经过Dio.get()就能够完结一个Get类型的接口恳求,它回来的是Future类型的目标,看到Future类型小伙伴是不是就知道如何展现接口数据了,只需求经过FutureBuilder的形式就能够完结接口数据的展现,下面直接贴代码。
接口数据展现
class _DioState extends State<DioWidget> {
@override
Widget build(BuildContext context) {
return buildScaffold(
context,
Center(
child: FutureBuilder(
future: fetchArticle(),
builder: (context, result) {
ConnectionState state = result.connectionState;
if (state == ConnectionState.done) {
Article article = Article.fromJson(result.data?.data);
return ListView.builder(
itemCount: article.data?.size ?? 0,
itemBuilder: (context, index) {
return ListTile(
title: Text("${article.data!.datas?[index].title}"),
);
});
} else {
return const CircularProgressIndicator();
}
}),
),
);
}
}
上述代码中在第8行出将接口恳求的Future传入给FutureBuilder,然后在第12行处进行数据的Json解析,Article.fromJson()办法就是经过Json To Dart生成出来的,不需求小伙伴自己手动编写,这样咱们就拿到了最终想要的数据类型,经过Article目标制作了一个列表界面,每个Item只显示文章的标题,实际效果见下方GIF。
到此为止咱们就经过Dio+FutureBuilder的办法完结了一个接口恳求,并且将恳求后的数据展现到界面上,整体来说仍是比较简略的,哈哈~得益于Flutter的呼应式布局。
写在最终
本篇文章首要介绍了Flutter中FutureBuilder和StreamBuilder完结异步加载UI的功能,并且经过Dio完结了接口数据的加载和展现,期望能够给阅览的小伙伴们带来一点协助,后续会按部就班逐渐触摸Flutter更多的常识。
我是Taonce,假如觉得本文对你有所协助,帮助关注、赞或许收藏三连一下,谢谢~