由于不是专门做App研发的,可能思维比较狭隘,以下两点估计能覆盖大部分的需求场景:
- 基于HTTP网络请求的增删改查
- 基于本地数据库,比如sqlite的增删改查
。。。。。。别打我,也可能就我自己这么认为。
这个应该前端的同学很熟悉,从以前的事件监听,promise到现在的Future都是异步开发的思想。说白了就是:
我封装了一个任务和参数交给系统,你把这个事情做了,成功后做啥,失败后做啥。在任务执行期间我就可以做别的事情了。
异步在Flutter中,或者说是在Dart的底层机制中是无所不在的,因此它是所有功能研发的基础。
void main () {
Future(() {
print('future craeted');
return 12;
}).then((data) {
print('received data $data');
});
print('main func done');
}
这里输出的顺序应该是:
- main func done
- future created
- received data 12
因为,Future((){}).then((){});
仅做了封装了一个任务并交给Dart,随后立马运行到 print('main func done');
这行,因此main func done 是最先输出的。
其次是异步代码的编排,如果仅仅依靠Future的then和catchError, 实现异步的调度,一旦需要多个异步操作先后依赖则很容易出现如下代码:
futurefunc1().then((data1){
futurefunc2(data1).then((data2){
futurefunc3(data2).then((){}).catchError((error){});......
}).catchError((error){
print('futuer 2 error');
});
}).catchError((error){
print('future 1 error');
});
代码是很难读懂的,此时async出现了
futurefunc1() async {}
futurefunc2(data1) async {}
futurefunc3(data2) async {}
main() async {
var data1 = await futurefunc1();
var data2 = await futurefunc2(data1);
var data3 = await futurefunc3(data2);
}
这样异步任务的依赖关系就很明白了。
在此基础上,http,sqlite等相关工具调用函数返回Future就很容易理解了。
这个是最直接的思路,通过界面Widget绑定变量,在state改变时候重新绘制就行
class BasePage extends StatefulWidget {
@override
_BasePageState createState() =>_BasePageState();
}
class _BasePageState extends State<BasePage> {
// 变量
bool _loading = false;
String _result = '';
@override
initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Container(
// 载入过程中显示载入中,结束后显示获得的结果
child: _loading? Text('载入中'): Text(_result);
);
}
/// 页面逻辑
loadData() {
setState((){
_loading = true;
});
getData().then((data){
setData((){
_loading = false;
_result = data;
});
}).catchError((error){
print('error $error');
setData((){
_loading = false;
_result = 'Oops';
});
});
}
/// 某种耗时的获取数据的方法比如http或者sql
Future<String> getData() async {
return 'takes time to get some thing';
}
}
1)方法仍然需要用户手动维护载入状态,执行中啥样,成功啥样,错误啥样,都需要自己setState来操作,比较麻烦。
Flutter官方提供了基于Future的Widget构造方法,用户仅需要提供Future的来源,各种状态的显示样式即可,整个loadData页面逻辑函数就可以去掉了。上述同样的功能即变为 :
class BasePage extends StatefulWidget {
@override
_BasePageState createState() =>_BasePageState();
}
class _BasePageState extends State<BasePage> {
// 变量
bool _loading = false;
String _result = '';
@override
Widget build(BuildContext context) {
/// 这里是FutureBuilder 因为Future提供函数getData()返回的是Future
/// 其实可以不指定String类型, 即FutureBuilder(), 这样默认是dynamic类型
return FutureBuilder<String>(
future: getData,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Oops');
} else if(snapshot.hasData){
return Text(snapshot.data);
} else {
return Text('载入中');
}
}
);
}
/// 某种耗时的获取数据的方法比如http或者sql
Future<String> getData() async {
return 'takes time to get some thing';
}
}
如果界面的值不是一次发生变化,而是在一个时期内会有多次变化,则可以使用StreamBuilder, 这个控件在后期会提到。
控件包管理方面,Google提供了pub,和Java的Maven, Gradle类似,在Flutter项目的yaml文件中声明dependency并标明版本即可把控件依赖加入到项目中。 以下提供Http和Sql增删改查的基本工具。
这个是Flutter上最为流行的Http工具库,封装了很多基本方法,get、post、文件上传、文件下载等等
项目地址
Dio
Dio dio = Dio();
dio.get('http://www.baidu.com'); // 返回Future
dio.post('http://api.baidu.com', data: {"param":value}); // 返回Future
// ......还有很多很多,请见官方文档
这个是Flutter上Sqlite实现工具库,同样也是封装得很完完善的库了。
项目地址
sqflite
Database db = await openDatabase(path,readOnly: false);
db.rawQuery('SELECT * FROM table'); // 返回Future>
// .... 还有很多
结合上边的 Future和FutureBuilder,想必小伙伴们已经知道怎么做了吧。