内容简介:主要是学习FutureBuilder的使用,利用FutureBuilder来实现懒加载,并可以监听加载过程的状态 这个Demo是加载玩Android的一个页面的列表数据经常有这些场景,就是先请求网络数据并显示加载菊花,拿到数据后根据请求结果显示不同的界面, 比如请求出错就显示error界面,响应结果里面的列表数据为空的话,就显示数据为空的界面,有数据的话, 就把列表数据加载到列表中进行显示.future就是一个定义的异步操作,注意要带上泛型,不然后面拿去snapshot.data的时候结果是dynamic
主要是学习FutureBuilder的使用,利用FutureBuilder来实现懒加载,并可以监听加载过程的状态 这个Demo是加载玩Android的一个页面的列表数据
1.需求场景
经常有这些场景,就是先请求网络数据并显示加载菊花,拿到数据后根据请求结果显示不同的界面, 比如请求出错就显示error界面,响应结果里面的列表数据为空的话,就显示数据为空的界面,有数据的话, 就把列表数据加载到列表中进行显示.
2.需要用到的控件
- 下拉刷新RefreshIndicator,列表ListView,这里不做过多介绍
- FutureBuilder:Flutter应用中的异步模型,基于与Future交互的最新快照来构建自身的widget 官方文档: docs.flutter.io/flutter/wid…
const FutureBuilder({ Key key, this.future,//获取数据的方法 this.initialData, @required this.builder//根据快照的状态,返回不同的widget }) : assert(builder != null), super(key: key); 复制代码
future就是一个定义的异步操作,注意要带上泛型,不然后面拿去snapshot.data的时候结果是dynamic的 snapshot就是future这个异步操作的状态快照,根据它的connectionState去加载不同的widget 有四种快照的状态:
enum ConnectionState { //future还未执行的快照状态 none, //连接到一个异步操作,并且等待交互,一般在这种状态的时候,我们可以加载个菊花 waiting, //连接到一个活跃的操作,比如stream流,会不断地返回值,并还没有结束,一般也是可以加载个菊花 active, //异步操作执行结束,一般在这里可以去拿取异步操作执行的结果,并显示相应的布局 done, } 复制代码
下面的官方的例子。
FutureBuilder<String>( future: _calculation, // a previously-obtained Future<String> or null builder: (BuildContext context, AsyncSnapshot<String> snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return Text('Press button to start.'); case ConnectionState.active: case ConnectionState.waiting: return Text('Awaiting result...'); case ConnectionState.done: if (snapshot.hasError) return Text('Error: ${snapshot.error}'); return Text('Result: ${snapshot.data}'); } return null; // unreachable }, ) 复制代码
3.实现思路,布局方式
-
网络请求:利用Dio库来请求玩Android的知识体系列表,api: www.wanandroid.com/tree/json
-
序列化json:利用json_serializable来解析返回的json数据
-
布局:加载过程显示CircularProgressIndicator,加载完成把数据显示到ListView中, 加载为空或者加载出错的话,显示相应的提示页面,并可以进行重试请求 一般。我们的列表页面都是有下拉刷新的功能,所以这里就用RefreshIndicator来实现。
4.代码实现
import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; import 'entity.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, ), home: FutureBuilderPage(), ); } } class FutureBuilderPage extends StatefulWidget { @override _FutureBuilderPageState createState() => _FutureBuilderPageState(); } class _FutureBuilderPageState extends State<FutureBuilderPage> { Future future; @override void initState() { // TODO: implement initState super.initState(); future = getdata(); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("知识体系"), actions: <Widget>[ new IconButton( icon: Icon( Icons.search, color: Colors.white, ), onPressed: null) ], ), body: buildFutureBuilder(), floatingActionButton: new FloatingActionButton(onPressed: () { setState(() { //测试futurebuilder是否进行没必要的重绘操作 }); }), ); } FutureBuilder<List<Data>> buildFutureBuilder() { return new FutureBuilder<List<Data>>( builder: (context, AsyncSnapshot<List<Data>> async) { //在这里根据快照的状态,返回相应的widget if (async.connectionState == ConnectionState.active || async.connectionState == ConnectionState.waiting) { return new Center( child: new CircularProgressIndicator(), ); } if (async.connectionState == ConnectionState.done) { debugPrint("done"); if (async.hasError) { return new Center( child: new Text("ERROR"), ); } else if (async.hasData) { List<Data> list = async.data; return new RefreshIndicator( child: buildListView(context, list), onRefresh: refresh); } } }, future: future, ); } buildListView(BuildContext context, List<Data> list) { return new ListView.builder( itemBuilder: (context, index) { Data bean = list[index]; StringBuffer str = new StringBuffer(); for (Children children in bean.children) { str.write(children.name + " "); } return new ListTile( title: new Text(bean.name), subtitle: new Text(str.toString()), trailing: new IconButton( icon: new Icon( Icons.navigate_next, color: Colors.grey, ), onPressed: () {}), ); }, itemCount: list.length, ); } //获取数据的逻辑,利用dio库进行网络请求,拿到数据后利用json_serializable解析json数据 //并将列表的数据包装在一个future中 Future<List<Data>> getdata() async { debugPrint("getdata"); var dio = new Dio(); Response response = await dio.get("http://www.wanandroid.com/tree/json"); Map<String, dynamic> map = response.data; Entity entity = Entity.fromJson(map); return entity.data; } //刷新数据,重新设置future就行了 Future refresh() async { setState(() { future = getdata(); }); } } 复制代码
5.注意的问题和踩坑
- 防止FutureBuilder进行不必要的重绘:这里我采用的方法,是将getData()赋值给一个future的成员变量, 用它来保存getData()的结果,以避免不必要的重绘 参考文章: blog.csdn.net/u011272795/…
- FutureBuilder和RefreshIndicator的嵌套问题,到底谁是谁的child,这里我是把RefreshIndicator作为FutureBuilder 的孩子。如果将RefreshIndicator放在外层,FutureBuilder作为child的话,当RefreshIndicator调用onrefreh刷新数据并用 setState()去更新界面的时候,那FutureBuilder也会再次经历生命周期,所以导致获取数据的逻辑会被走两遍
以上所述就是小编给大家介绍的《Flutter之FutureBuilder的学习和使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MATLAB智能算法30个案例分析
史峰、王辉、胡斐、郁磊 / 北京航空航天大学出版社 / 2011-7-1 / 39.00元
MATLAB智能算法30个案例分析,ISBN:9787512403512,作者:史峰,王辉 等编著一起来看看 《MATLAB智能算法30个案例分析》 这本书的介绍吧!