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(),
    );
  }
}
相关推荐
Ranye1236 分钟前
从 JS 到 Dart:语法基础
javascript·flutter·dart
Aphelios3802 小时前
Linux 下 VIM 编辑器学习记录:从基础到进阶(下)
java·linux·学习·编辑器·vim
Best_Me072 小时前
【CVPR2024-工业异常检测】PromptAD:与只有正常样本的少样本异常检测的学习提示
人工智能·学习·算法·计算机视觉
日记成书2 小时前
详细介绍STM32(32位单片机)外设应用
stm32·学习
li星野3 小时前
std::thread的同步机制
开发语言·c++·学习
技术小齐3 小时前
网络运维学习笔记 021 HCIA-Datacom新增知识点02 SDN与NFV概述
运维·网络·学习
im长街4 小时前
Ubuntu22.04 - brpc的安装和使用
学习
知识分享小能手4 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
你可以叫我仔哥呀6 小时前
k8s学习记录:环境搭建(基于Kubeadmin)
学习·容器·kubernetes
试试看1686 小时前
自制操作系统前置知识汇编学习
汇编·学习