1.异步代码
2.后台开线程执行代码
3.网络请求
4.长时间的任务添加进度条
1.异步代码
在 Android 中,不开线程,所有代码都走主线程执行;在 Flutter 也是一样,不开线程,Dart 代码永远主线程执行。
我们可以通过 async / await 来实现异步操作,比如网络请求:
loadData() async {
String url="https://xx";
http.Response response = await http.get(url);
setState(() {
widgets = json.decode(response.body);
});
}
await 网络请求完成,调用 setState() 更新 UI。
下面的例子,请求网络并且展示数据,需要在 pubspec.yaml 添加依赖:
dependencies:
# 加这一行
http: ^0.12.0+1
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
添加完记得点击 Pub get :
添加下面的代码,注意里面的包引入变化:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List widgets = [];
@override
void initState() {
// TODO: implement initState
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context,int position){
print("itemBuilder方法");
return getRow(position);
},
),
);
}
getRow(int i) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row ${widgets[i]["title"]} "),
);
}
loadData() async {
String url="https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(url);
setState(() {
widgets = json.decode(response.body);
});
}
}
新版本运行的时候可能有下面的报错:
2.后台开线程执行代码
一般访问磁盘、网络请求或做 I/O 操作,可以用 async / await 来完成。
如果执行长时间复杂任务,可以用 Isplate 避免阻塞 event loop。
在 Flutter 中,async 关键字把方法声明为异步方法,通过 await 关键字等待该异步方法执行完成。
Isolate 是分离的运行线程,并且不和主线程共享内存。也不能访问主线程中的变量和更新 UI 。
下面简单展示, Isolate 把数据返回给主线程更新 UI ,了解就可以,不用完全理解,后面用的多了自然就理解了:
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List widgets = [];
@override
void initState() {
// TODO: implement initState
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context,int position){
print("itemBuilder方法");
return getRow(position);
},
),
);
}
getRow(int i) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row ${widgets[i]["title"]} "),
);
}
loadData() async {
//ReceivePort接受传入消息
ReceivePort receivePort = ReceivePort();
//创建生成与当前Isolate共享代码的Isolate
await Isolate.spawn(dataLoader, receivePort.sendPort);
//流的第一个元素
SendPort sendPort = await receivePort.first;
//第一个元素回收后监听会关闭,所以要新创建一个ReceivePort接受传入消息
ReceivePort response = ReceivePort();
//向第一个ReceivePort发送异步消息
sendPort.send(["https://jsonplaceholder.typicode.com/posts",response.sendPort]);
//获取发送来的数据
List msg = await response.first;
setState((){
widgets = msg;
});
}
//
static dataLoader(SendPort sendPort) async{
ReceivePort port = ReceivePort();
sendPort.send(port.sendPort);
await for (var msg in port){
String data = msg[0];
SendPort replyTo = msg[1];
String dataUrl = data;
http.Response response = await http.get(dataUrl);
replyTo.send(json.decode(response.body));
}
}
}
3.网络请求
实现网络请求,上面已经说明了;
需要在 pubspec.yaml 添加依赖:
dependencies:
# 加这一行
http: ^0.12.0+1
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
添加完记得点击 Pub get :
代码中先引入包:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
实现网络请求的方法:
loadData() async {
String url="https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(url);
setState(() {
widgets = json.decode(response.body);
});
}
4.长时间的任务添加进度条
Flutter 中,对应的 widget 叫 ProgressIndicator。通过布尔 flag 控制展示进度,开始任务更新进度条。结束后隐藏。
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List widgets = [];
@override
void initState() {
// TODO: implement initState
super.initState();
loadData();
}
showLoadingDialog() {
return widgets.length == 0;
}
getBody() {
if (showLoadingDialog()) {
return getProgressDialog();
} else {
return getListView();
}
}
getProgressDialog() {
return Center(child: CircularProgressIndicator());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: getBody());
}
ListView getListView() => ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
print("itemBuilder方法");
return getRow(position);
});
getRow(int i) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row ${widgets[i]["title"]} "),
);
}
loadData() async {
String url = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(url);
setState(() {
widgets = json.decode(response.body);
});
}
}