Says flutter---07dart异步和网络请求

445 阅读5分钟

01-Dart异步

Dart的异步模型

  • Dart是单线程
    1.如何处理耗时操作?
      多线程处理:java、c++;
      单线程+时间循环:JavaScript、Dart。
    2.单线程如何处理耗时操作?
      单线程进行异步操作,通过时间循环进行耗时操作。
    
  • dart事件循环
    即将需要处理的一系列事件,包括点击事件、IO事件和网络事件等放在一个事件队列中。不断的从事件队列中取出事件,并执行其对应需要执行的代码块,直到事件队列清空位置。
    

Dart的异步操作

  • Future
    • 基本使用
      1.如何理解?
        可以将Future理解成Promise,把耗时的操作放到用Future修饰的函数中,通过.then获取请求的结果,通    过.catchError捕获异常。
      2.示例代码:
        import "dart:io";
        main(List<String> args) {
          var future = getNetworkData();
          Future.then((value) {
            print(value);  //输出结果为'hello'
          }).catchError((err) { 
            print(err);  //捕获异常,输出结果为'网络请求出现错误'
          });
        }
        Future<String> getNetworkData() {
          return Future<String>(() {
            sleep(Duration(seconds: 3));
            // return "hello";
            throw Exception("网络请求出现错误"); // 不再返回结果,而是出现异常
          });
        }
      
    • Future链式调用
      import "dart:io";
      main(List<String> args) {
        print("main function start");
        getNetworkData().then((value1) {
          print(value1);
          return "data2";
        }).then((value2) {
          print(value2);
          return "data3";
        }).then((value3) {
          print(value3);
        });
        print("main function end");
      }
      Future<String> getNetworkData() {
        return Future<String>(() {
          sleep(Duration(seconds: 3));
          // 不再返回结果,而是出现异常
           return "data1";
        });
      }
      ////////////////////////////////////
      打印结果如下:
        main function start
        main function end
        // 3s后拿到以下结果
        data1
        data2
        data3 
      
    • Future其他API
      1.Future.value(val):直接获取一个完成的Future,该Future会直接调用then的回调函数。
        Future.value("哈哈哈").then((val) {
          print(val);  //输出 哈哈哈
        });
      2.Future.error(object):直接获取一个完成的Future,但是是一个发生异常的Future,该Future会直接调用catchError的回调函数。
        Future.error(Exception("错误信息")).catchError((err) {
          print(err);  //输出 Exception: 错误信息
        });
      3.Future.delayed(时间, 回调函数):在延迟一定时间时执行回调函数,执行完回调函数后会执行then的回调。
        Future.delayed(Duration(seconds: 3), () {
          return "3秒后的信息";
        }).then((value) {
          print(value);  //3秒后输出 3秒后的信息
        });
      
  • await和async
    1.即通过同步的代码实现异步的请求。
    2.示例:
      Future<String> getNetworkData() async {
        var result = await Future.delayed(Duration(seconds: 3), () {
          return "network data";
        });
        return "请求到的数据:" + result;
      }
    3.await必须使用在async修饰的函数中;
      async函数会返回一个Future。
    

Dart的异步补充

  • 任务执行顺序之微任务队列
    1.微任务队列的优先级高于事件队列;
    2.Flutter开发中,所有的外部事件任务都在事件队列中,如IO、计时器、点击以及绘制事件等;微任务通常来源于Dart内部,并且非常少;
    3.Dart单线程中,代码如何执行?
      1)dart入口是main函数,即main函数中的代码优先执行;
      2main函数执行完后,会启动一个事件循环,启动后开始执行队列中的任务;
      3)按照先进先出的顺序,执行微队列中的所有任务,然后执行事件队列的所有任务。
    
  • 多核cpu的利用
    1.Isolate的理解
      Dart是单线程的,该线程有自己可以访问的空间以及需要运行的事件循环,将这个空间称之为Isolate,每个Isolate都有自己的事件循环和事件队列,并且他们之间不存在资源共享。但是对于多核cpu来说,如果只有一个Isolate,那么相当于一种资源浪费,故可以自己创建Isolate。
    2.创建Isolate
      main(List<String> args) {
        Isolate.spawn(foo, "Hello Isolate");
      }
      void foo(info) {
        print("新的isolate:$info");
      }
    3.Isolate通信机制(Flutter内部封装了支持Isolate创建和双向通信的函数,仅能用于Flutter项目)
      main(List<String> args) async {
        int result = await compute(powerNum, 5);
        print(result);
      }
      int powerNum(int num) {
        return num * num;
      }
      ////////////////////////////////////////
      注意:compute里面接受的函数(这里是powerNum)必须是全局的,否则会报错!!!!!!!!!
    

02-Flutter网络请求

HttpClient类(一般不使用)

是Dart中自带的请求类。
void requestNetwork() async {
// 1.创建HttpClient对象
final httpClient = HttpClient();
// 2.构建请求的url
final url = Url.parse("http://123.207.32.32:8000/api/v1/recommend");
// 3.构建请求
final request = await httpClient.getUrl(url);
// 4.发送请求,必须
final response = await request.close();
  if (response.statusCode == HttpStatus.ok) {
    print(await response.transform(utf8.decoder).join());
  } else {
    print(response.statusCode);
  }
}

http库(不经常用)

1.是Dart官方提供的请求类,但是没有默认集成到Dart的SDK中,需要在pubspec安装依赖。
2.示例:
  import'package:http/http.dart'as http;
  void httpNetwork() async {
    // 1.创建Client
    final client = http.Client();
    // 2.构建url
    final url = Url.parse("http://123.207.32.32:8000/api/v1/recommend");
    // 3.发送请求
    final response = await client.get(url);
    // 4.获取结果
    if (response.statusCode == HttpStatus.ok) {
      print(response.body);
    } else {
      print(response.statusCode);
    }
  }

dio三方库(经常使用)

1.是Dart的请求库,支持Restful API、FormData、拦截器、请求取消、cookie管理、文件上传/下载、超时、自定义适配等。
2.使用:
  先在pubspec中写入依赖;
    dio:^3.0.1
  封装dio库。
    1)配置基本信息:http_config.dart
      class HTTPConfig {
	      static const baseURL = "https://httpbin.org";
	      static const timeout = 5000;
      }
    2)封装请求:http_request.dart
      import'package:dio/dio.dart';
      //  import'package:testflutter001/service/config.dart';
      class HttpRequest {
        // 配置参数:路径、请求时间、contentType、headers等
        static final BaseOptions options = BaseOptions(
      											  baseUrl: HTTPConfig.baseURL, 
      											  connectTimeout: HTTPConfig.timeout
                                                   );
		  static final Dio dio = Dio(options);  //创建一个Dio实例并且配置,该配置是公共配置
        static Future<T> request<T>(String url,{
      										String method = 'get', 
                                              Map<String, dynamic> params, 
                                              Interceptor inter
                                              }) async {
          // 1.每个请求还可以单出配置,该单独配置可以覆盖公共配置中的信息
          final options = Options(method: method);
          //  全局拦截器
          // 创建默认的全局拦截器
          Interceptor dInter = InterceptorsWrapper(
            onRequest: (options) {
               // 在进行任何网络请求的时候, 可以添加一个loading显示
              // 很多页面的访问必须要求携带Token,那么就可以在这里判断是有Token
              // 对参数进行一些处理,比如序列化处理等
              print("拦截了请求");
              return options;
           },
           onResponse: (response) {
             print("拦截了响应");
             return response;
           },
           onError: (error) {
             print("拦截了错误");
             return error;
           }
         );
         List<Interceptor> inters = [dInter];
         //请求单独拦截器
         if (inter != null) {
             inters.add(inter);
         }
         //统一添加到拦截器中
         dio.interceptors.addAll(inters);
        // 2.发送网络请求
         try {
           Response response = await dio.request<T>(url, queryParameters: params, options: options);
           return response.data;
         } on DioError catch(e) {
           return Future.error(e);
         }
        }
        //  static void get() {
        //    request(url, method: get);
        //  }
      }
    3)具体使用:
      HttpRequest.request("https://httpbin.org/get", params: {"name": "why", 'age': 18},inter:InterceptorsWrapper(onRequest:(){},onResponse:(){},onError:(){},).then((res) {
        print(res);
      });
      HttpRequest.request("https://httpbin.org/post",method: "post", params: {"name": "why", 'age': 18}).then((res) {
        print(res);
      });