内容简介:主要是学习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的学习和使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML Dog
Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99
For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!