Flutter学习11 - Future 与 FutureBuilder

1、Future

  • 可以利用 Future 实现异步调用

1.1、Future 的两种形式

自定义一个结果类

dart 复制代码
class Response {
  String _data;

  Response(this._data);
}

自定义方法实现 Future

dart 复制代码
Future<Response> testFuture() {
  var random = Random();
  int randomNumber = random.nextInt(10);
  if (randomNumber % 2 == 0) {
    return Future.value(Response('success: 偶数 $randomNumber'));
  } else {
    return Future.error('error: 奇数 $randomNumber');
  }
}
(1) then - onError
dart 复制代码
void main() {
  testFuture().then((value) {
    print(value._data);
  }, onError: (e) {
    print('1、onError: $e');
  });
}
(2) then - catchError
dart 复制代码
void main() {
  testFuture().then((value) {
    print(value._data);
  }).catchError((e) {
    print('2、catchError: $e');
  });
(3) 注意:当 onError 与 catchError 同时存在,只会调用 onError
dart 复制代码
void main() {
  //注:当 onError 与 catchError 同时存在,只会执行 onError
  testFuture().then((value) {
    print(value._data);
  }, onError: (e) {
    print('3、onError: $e');
  }).catchError((e) {
    print('3、catchError: $e');
  });
}

1.2、Future.whenComplete

then - catchError - whenComplete 类似于 try - catch - finally

dart 复制代码
Future<String> testFutureWhenComplete() {
  var random = Random();
  int randomNumber = random.nextInt(10);
  if (randomNumber % 2 == 0) {
    return Future.value('success: 偶数 $randomNumber');
  } else {
    return Future.error('error: 奇数 $randomNumber');
  }
}
dart 复制代码
void main(){
  testFutureWhenComplete()
      .then(print)
      .catchError(print)
      .whenComplete(() {
    print('完成!!!');
  });
}

1.3、Future.timeout

dart 复制代码
Future<String> testFutureTimeout() {
  return Future.delayed(const Duration(seconds: 2), () {
    var random = Random();
    int randomNumber = random.nextInt(10);
    if (randomNumber % 2 == 0) {
      return Future.value('success: 偶数 $randomNumber');
    } else {
      return Future.error('error: 奇数 $randomNumber');
    }
  });
}
dart 复制代码
void main(){
  //TimeoutException after 0:00:01.000000: Future not completed
  // Done!!!
  testFutureTimeout()
      .timeout(const Duration(seconds: 1))
      .then(print)
      .catchError(print)
      .whenComplete(() {
    print('Done!!!');
  });
}

2、FutureBuilder

  • FutureBuilder 是一个将异步操作和异步UI结合在一起的控件

2.1、构造函数

dart 复制代码
FutureBuilder({Key key, Future<T> future, T initialData, @required AsyncWidgetBuilder<T> builder })
initialData Future完成前的初始化数据
future 异步操作,返回Future对象
builder 异步UI
builder
  • builder函数接受两个参数BuildContext context 与 AsyncSnapshot snapshot,返回一个widget
dart 复制代码
final AsyncWidgetBuilder<T> builder;
dart 复制代码
typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext context, AsyncSnapshot<T> snapshot);
AsyncSnapshot 包含信息
  • connectionState:表示与异步计算的连接状态,ConnectionState有四个值:none,waiting,active,done
none 当前未连接到异步计算
waiting 连接到异步计算等待交互
active 异步计算进行中
done 异步计算完成
  • data:异步计算接收到的最新数据
  • error:异步计算接收到的最新错误数据
  • hasData:检查是否包含非空数据
  • hasError:检查是否包含错误值

2.2、代码示例

FutureBuilderDemo.dart

dart 复制代码
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class FutureBuilderDemo extends StatefulWidget {
  const FutureBuilderDemo({super.key});

  @override
  State<FutureBuilderDemo> createState() => _FutureBuilderDemoState();
}

class _FutureBuilderDemoState extends State<FutureBuilderDemo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FutureBuilder Demo'),
      ),
      body: FutureBuilder<PhoneEntity>(
        future: _doGet(),
        builder: (BuildContext context, AsyncSnapshot<PhoneEntity> snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:
              return const Text('状态:无');
            case ConnectionState.waiting:
              //进度条
              return const Center(
                child: CircularProgressIndicator(),
              );
            case ConnectionState.active:
              return const Text('状态:激活');
            case ConnectionState.done:
              if (snapshot.hasError) {
                //失败
                return Text(
                  '${snapshot.error}',
                  style: const TextStyle(color: Colors.red),
                );
              } else {
                return Column(
                  children: [
                    Text('code: ${snapshot.data!.code}'),
                    Text('city: ${snapshot.data!.data!.city}'),
                    Text('province: ${snapshot.data!.data!.province}'),
                    Text('sp: ${snapshot.data!.data!.sp}'),
                  ],
                );
              }
          }
        },
      ),
    );
  }

  Future<PhoneEntity> _doGet() async {
    var url =
        Uri.parse('https://cx.shouji.360.cn/phonearea.php?number=17688888888');
    var response = await http.get(url);
    if (response.statusCode == 200) {
      //请求成功
      try {
        var json = response.body;
        var map = jsonDecode(json);
        var entity = PhoneEntity.fromJson(map);
        return Future.value(entity);
      } catch (e) {
        return Future.error('数据异常: ${e.toString()}');
      }
    } else {
      //请求失败
      return Future.error('请求失败 ! ! !');
    }
  }
}

/**********************/

///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class PhoneEntityData {
/*
{
  "province": "广东",
  "city": "广州",
  "sp": "联通"
}
*/

  String? province;
  String? city;
  String? sp;

  PhoneEntityData({
    this.province,
    this.city,
    this.sp,
  });

  PhoneEntityData.fromJson(Map<String, dynamic> json) {
    province = json['province']?.toString();
    city = json['city']?.toString();
    sp = json['sp']?.toString();
  }

  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['province'] = province;
    data['city'] = city;
    data['sp'] = sp;
    return data;
  }
}

class PhoneEntity {
/*
{
  "code": 0,
  "data": {
    "province": "广东",
    "city": "广州",
    "sp": "联通"
  }
}
*/

  int? code;
  PhoneEntityData? data;

  PhoneEntity({
    this.code,
    this.data,
  });

  PhoneEntity.fromJson(Map<String, dynamic> json) {
    code = json['code']?.toInt();
    data =
        (json['data'] != null) ? PhoneEntityData.fromJson(json['data']) : null;
  }

  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['code'] = code;
    if (data != null) {
      data['data'] = this.data!.toJson();
    }
    return data;
  }
}

main.dart

dart 复制代码
import 'package:flutter/material.dart';

import 'FutureBuilderDemo.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Leon Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const FutureBuilderDemo(),
    );
  }
}
相关推荐
自强的小白1 小时前
vlan(局部虚拟网)
网络·学习
一只乔哇噻1 小时前
java后端工程师进修ing(研一版 || day41)
java·开发语言·学习·算法
知识分享小能手1 小时前
React学习教程,从入门到精通,React 使用属性(Props)创建组件语法知识点与案例详解(15)
前端·javascript·vue.js·学习·react.js·前端框架·vue
知识分享小能手8 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
茯苓gao10 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾11 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT11 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa11 小时前
HTML和CSS学习
前端·css·学习·html
看海天一色听风起雨落12 小时前
Python学习之装饰器
开发语言·python·学习
speop13 小时前
llm的一点学习笔记
笔记·学习