高级

extension(扩展)

  • extension 关键字在 Dart2.7 及其以上才支持
  • sdk ">=2.7.0<3.0.0"
  • extension 可以扩展对象的内容
    • extension StringExtension on String{// 扩展的内容}
    • 扩展不仅可以定义方法,还可以定义 setter,getter,operatior
  • 使用
    • 声明扩展
    • 引入扩展
    • 使用扩展(String.扩展内容)
//扩展内部类
extension StringExtension on String{
    //将字符串形式的数字,转成数字
    parseInt(){
        return int.parse(this);
    }
}
//扩展自定义类
class Person{
    say(){
        print('Say something');
    }
}
extension StudentPerson on Person{
    study(){
        print('student2')
    }
}
main(){
    String number = "20";
    print(number.parseInt(number));
    var p = Person();
    print(p.say());
    print(p.study);
}

call

  • 在类中可以声明 call 方法(方法名不能变)
  • 当我们将类的实例,用作函数时候,会自动调用 call 方法

image

main(){
    var phone = IOSPhone();
    phone('911');//将类对象用作函数名 调用call方法
}
class IOSPhone{
    call(String num){
        print('phone number is $num');
    }
}

noSuchMethod

  • 当我们调用了一个类的,未定义的方法时,Dart 会自动调用 noSuchMethod
  • 使用前提
    • 类中声明了 noSuchMethod(否则调默认的 noSuchMethod)
    • 实例化对象必须用 dynamic 来修饰
      • dynamic p = Person();
    • 调用的是未定义方法(p.undefinedMethod())
class Person{
    say(){
        print('say something');
    }
    
    noSuchMethod(Invocatio invocation){
        print('未定义的方法');
        return super.noSuchMethod(invocation);
    }
}
main(){
    var p = Person();// dynamic p = Person();
    print(p.say());
    print(p.study());//这里会报错 为了避免报错Person中增加 noSuchMethod var改成 dynamic
}

hashCode

  • hashCode 是 Dart 对象的唯一标识
  • hashCode 表示未一串数字
  • Dart 中的每个对象都有 hashCode
  • 我们可以通过 hashCode 来判断两个对象是否相等
class Person{
    say(){
        print('Say something');
    }
}


main(){
    var p1 = Person();
    print(p1.hashCode);


    //单例
    var ps1 = PersonSingleton();
    print(ps1.hashCode);
    var ps2 = PersonSingleton();
    print(ps2.hashCode);
    print(ps1==ps2);// true
}

//单例
class PersonSingleton{
    static PersonSingleton instance;
    PersonSingleton._internal();
    static getInstance(){
        if(instance ==null){
            instance = PersonSingleton._internal();
        }
    }
    factory PersonSingleton()=>getInstance();<int>
}

typedef (type define 或 type defination 缩写)

  • typedef 可以用来自定义类型(别名)
  • 语法
    • typedef function_name(parameters);
    • typedef variable_name = List<int>; //2.13 之后
  • 版本声明
    • sdk:">=2.13.0<3.0.0"
    • 2.13 之前,typedef 仅限于函数类型
    • 2.13 之后,typedef 可以定义非函数类型
typedef MathOperation(int a,int b);
add(int a,int b){
    print('加法运算');
    return a+b;
}
add3(int a,int b,c int){
    print('加法运算');
    return a+b;
}
main(){
    print(add is MathOperation);//true
    print(add3 is MathOperation);//false
    print(add is Function);//true
    print(add3 is Function);//true
}

异步编程

  • 单线程(EventLoop)
  • Isolate 多线程
  • Future
  • Stream
  • Async/Await
  • Generator

单线程 EventLoop

  • Dart 单线程的核心包括:单线程,微任务和宏任务
    • 微任务队列
      • 微任务队列包含微任务,主要通过 scheduleMicrotask 来调度。
    • 事件队列
      • 事件队列包含外部时间,例如 I/O Timer 绘制事件等
  • 同步和异步
    • 同步(4*100 米)
    • 异步(100 米中有 8 个跑道)

image

跟浏览器的差不多

image

Isolate 多线程

  • Isolate 是 Dart 中的线程
    • Dart 中的线程是以隔离(Isolate)的方式存在的
    • 每个 Isolate 都有自己独立的,私有的内存块( 多个线程不共享内存)
    • 没有共享内存,就不需要竞争资源,就不需要锁(不用担心死锁问题)
  • 所有的 Dart 代码,都运行在 Isolate 中
    • Isolate 提供了 Dart|Fluter 的运行环境
    • 微任务队列,事件队列,事件轮询(EventLoop)都在 Isolate 中运行
  • 多线程经常用来解决耗时较长的异步任务

image

Isolate 多线程-创建

Isolate 类来管理线程(创建,暂停 杀死 Isolate 线程)

  • Isolate.spawn() 创建线程 直接调用当前文件中的函数
  • Isolate.spawnUri() 创建线程调用另外文件中的函数
  • Isolate.pause() 暂停进程
  • Isolate.kill()
涉及函数:
  • Future<Isolate>Isolate.spawn(entryPoint,message)
    • import 'dart:isolate';
    • entryPoint (必须是一个顶层方法或静态方法)
    • message
      • 1.Dart 原始数据类型 如 null bool int double String 等
      • 2.SendPort 实例-ReceivePort().sendPort
      • 包含 1 和 2 的 list 和 map,也可以嵌套
  • compute()
    • import 'package:flutter/foundation.dart';
import 'dart:isolate';

main(){
    multiThread();
}
void multiThread(){
   print('multiThread start');
   print('当前线程:'+ Isolate.current.debugName);//main
   Isolate.spawn(newThread,'hello');
   Isolate.spawn(newThread,'hello2');//同一个线程,要使用不同的函数创建不同线程
   print('multiThread end');
}
void newThread(String message){
    print('当前线程:'+ Isolate.current.debugName);//newThread
    print(message);//hello
}

Isolate 多线程通信机制

  • Isolate 多线程之间,通信的唯一方式是 Port
  • ReceivePort 类
    • 初始化接受端口,创建发送端口,接受消息,监听消息,关闭端口
  • SendPort 类
    • 将消息发送给 ReceivePort
  • 通信方式
    • 单向通信(a->b)
    • 双向通信(a<->b)

image

image

单向通信

import 'dart:isolate';
main(){
    multiThread();
}
void multiThread(){
    print('multThread start');
    print('当前线程:'+ Isolate.current.debugName);
    ReceivePort r1 = ReceivePort();
    SendPort p1 = r1.sendPort;
    Isolate.spawn(newThread,p1);

    //接收新线程发送过来的消息
    //var msg = r1.first;
    //print('来自新线程的消息'+ msg.toString());
    //接受新线程消息2
    r1.listen((msg){
        print('来自新线程的消息'+ msg.toString());
        r1.close();//关闭端口 不然会处于阻塞状态
    })
    print('multiThread end');
}
void newThead(SendPort p1){
    print('当前线程:'+ Isolate.current.debugName);
    //发送消息给main线程
    p1.send('abc');
}



双向通信

import 'dart:isolate';
main(){
    multiThread();
}
void multiThread()async{
    print('multThread start');
    print('当前线程:'+ Isolate.current.debugName);
    ReceivePort r1 = ReceivePort();
    SendPort p1 = r1.sendPort;
    Isolate.spawn(newThread,p1);

    //接收新线程发送过来的消息
    //var msg = r1.first;
    //print('来自新线程的消息'+ msg.toString());
    //接受新线程消息2
    //r1.listen((msg){
    //    print('来自新线程的消息'+ msg.toString());
     //   r1.close();//关闭端口 不然会处于阻塞状态
    //})
    SendPort p2 = await r1.fist;
    //p2.send('来自主线程的消息');
    var msg = await sendToReceive(p2,'hello');
    print('主线程接收到:$msg');
    print('multiThread end');
}
void newThead(SendPort p1)async{
    print('当前线程:'+ Isolate.current.debugName);
    ReceivePort r2 = ReceivePort();
    Sendport p2 = r2.sendPort;
    p1.send(p2);
    //r2.listen(message){
     //   print(message);//来自主线程消息
   // }
    await for (var msg in r2){
        var data = msg[0];
        print('新线程收到了来之主线程的消息:$data');
        SendPort replayPort = msg[1];
        replayPort.send(data);
    }
}

Future sendToReceive(SendPort port,msg){
    print('发送消息给新线程'+msg.toString());
    ReceivePort response = ReceivePort();
    port.send([msg,response.sendPort]);//可以传普通消息也可以是数组
    return response.fist;
}



Isolate.spawnUri

main(){
    start();
    //执行耗时的任务
    newIsolate();
    init();
}
start(){
    print('启动时间'+ DateTime.now().microsecondsSinceEpoch.toString());
}
newIsolate() async {
    print('新线程创建');
    ReceivePort r = ReceivePort();
    SendPort p = r.sendPort;
    //创建新线程
    Isolate childIsolate = await Isolate.spawnUri(
            Uri(path:"childIsolate.dart"),
            ['data1','data2','data3'],
            p
        );
    //监听消息
    r.listen((message){
        print('主线程接收到数据 $message[0]');
        if(message[1]==1){
            //异步任务正在处理
        }else if(message[1]==2){
            r.close();//关闭端口
            childIsolate.kill(); //释放线程
            print('子线程已经释放');
        }
    })
}

init(){
    print('项目初始化')
}


childIsolate.dart文件
import 'dart:isolate';
main(List<String> args,SendPort mainSendPort){
    print('新线程接受到的参数:$args');
    mainSendPort.send(['开始执行异步操作',0]);
    sleep(Duration(1)); //延时一秒
    mainSendPort.send(['加载中',1]);
    sleep(Duration(1));
    mainSendPort.send(['异步任务完成',2]);
}


Future(类似 promise)

  • Future 是 Dart 中的类,我们可以通过 Future 实例,凤凰钻杆一些异步任务
  • Future 的含义是未来,未来要执行的一些任务,我们可以放到 Future 中
  • Future 有三种状态
    • 未完成(Uncompleted)
    • 已完成,并返回数据(Completed with data)
    • 已完成,但返回报错(Completed with error)

获取 Future 实例

  • 自动返回
    • final myFuture = http.get();
    • final myFuture = SharedPreferences.getInstance;
  • 手动创建
    • final myFuture = Future((){return 123;});
    • final myFuture = Future.error(Exception());
    • final myFuture = Future.delayed(Duration(seconds:5),()=>123);
Future 状态相关的方法
  • 创建
    • uncompleted
  • then()
    • Completed with data
  • catchError()
    • Completed with error
  • whenComplete() //完成的时候才去带调用
    • Completed with data + Completed with error
main(){
    //创建Future 实例
    final f = new Future((){//new 关键字可以省略
        print('Create the future');
        print 123;
    });
    print(f);//Instance of 'Future<int>'
    f.then((value)=>print(value));
    print('Done with main');
}
main(){
    //创建Future 实例
    final f = Future.delayed(
        Duration(seconds:2),//延时两秒
        (){
            print 123;
            throw Error();
        }
    ).then(value){//Future.delayed
        print(value);
    }).catchError((err){
        print(err);
    },test:(error)=>error.runtimeType==String,//查看到报错的详细信息
    ).whenComplete((){
        print('All Completed');
    });
}

Future 执行顺序

  • Future 默认是一个异步任务,会被丢弃到时间队列(event queue)中
  • Future.sync()
    • 同步任务,同步执行(不会被丢到异步队列中)
  • Future.microtask()
    • 微任务,会丢到 microtask queue 中,优先级比时间任务高
  • Future.value(val)
    • val 是常量(等同于 microtask)
    • val 是异步(按照异步逻辑处理)
 main(){
    print('start');
    Future(()=>print('Future() task'));//异步 event queue

    Future.sync(()=>print('Future.sync() task'));// 同步
    Future.value(Future(()=>print('任务')));//如果value后面的值是异步则按照异步的逻辑处理
    Future.microtask(()=>print('Future.microtask() task'));//微任务 microtask queue
    Future.value('Futurevalue() const task').then((value)=>print(value));//如果value后面的值 是常量 那么Future.value创建的是微任务
    print('end');
}

Future 多任务

  • Future.any(futures)
    • 返回最先完成的 Future 结果
  • Future.wait(futures)
    • 等待所有 Future 执行完成,并手机所有 Future 的返回结果
  • Future.doWhile(action)
    • 按照条件便利执行多个 Future
  • Future.forEach(elements,action)
    • 遍历一个给定的集合,根据集合元素执行多个 Future
main(){
    print('start')
    Future.any([
        Future.delayed(Duration(seconds:4)).then((value)=>1),
        Future.delayed(Duration(seconds:2)).then((value)=>2),
        Future.delayed(Duration(seconds:3)).then((value)=>3),
    ]).then((value)=>print('最快的'+value.toString()));
    print('end');
}
main(){
    //等待所有异步任务完成
    Future.wait([
        Future.delayed(Duration(seconds:4)).then((value){
            print('Future 1');
            return 1;
        }),
        Future.delayed(Duration(seconds:2)).then((value){
            print('Future 2');
            return 2;
        }),
        Future.delayed(Duration(seconds:3)).then((value){
            print('Future 3');
            return 3;
        }),
    ]).then((value){
        print('所有Future 的执行结果是:'+value.toString());
    })
}
main(){
    var i = 0;
    Future.doWhile((){
        i++;
        return Future.delayed(Duration(seconds:2),(){
            print('Future.doWhile() $i 当前时间:'+ DateTime.now().microsecondsSinceEpoch.toString());
            return i<6;
        }).then(value){
             print(value);
            return value;
        });
    }).then((value){
        print('Future.doWhile() then:' + value.toString());
    });
}


main(){
    Future.forEach([1,2,3],(element){
        return Future.delayed(Duration(seconds:2),(){
            print('当前元素:$element');
            return element.toString()+'_AAA';
        }).then((value){
            print('处理后的结果 $value');
        });
    })
}

FutureBuilder

  • FutureBuilder 是 Fluter SDK 中提供的异步组件
    • FutureBuilder 是一个类,接受 Future 数据,并将数据渲染成界面
    • import 'package:flutter/material.dart';
  • FutureBuilder 中,有三个属性
    • future
    • initialData
    • builder(context,snapshot)

FutureBuilder-snapshot

  • snapshot.connectionState
    • ConnectionState.none(未连接异步任务)
    • ConnectionState.waiting(链接异步任务,等待交互)
    • ConnectionState.active(正在交互)
    • ConnectionState.done(异步任务完成)
  • snapshot.hasData(Completed with data)
    • snapshot.data
  • snapshot.hasError(Completed with error)

image

Stream

  • Stream 是 Dart 中的异步数据流,可以连续不断的返回多个数据
    • Future 是异步,但是只返回一个值
    • Stream 也是异步,可以返回多个值(数据流)
  • Stream 相关的 API
    • 通过 listen 进行数据监听
    • 通过 error 接收失败状态
    • 通过 done 来接受结束状态
Stream 类型
  • Single-Subscription(单一订阅)
    • 数据流只能被 listen 一次(listen 多次会报错)
    • StreamController().stream
    • Stream stream = Stream.fromIterable(data)
  • Broadcast(广播)
    • 数据流可以被 listen 多次
    • StreamController<int>.broadcast();
    • stream.asBroadcastStream()
import 'dart:async';
main(){
//创建单一订阅数据流
    final StreamController controller = StreamController();
    //第一次监听
    conroller.stream.listen((event){
       print('Data is $event')
    });
    //给数据流添加数据
    controller.sink.add('abc');
    controller.sink.add('123');
}

广播流

import 'dart:async';
main(){
    //创建广播流
    StreamController controller = StreamController.broadcast();
    //第一次监听
    conroller.stream.listen((event){
       print('Data is $event')
    });
    controller.sink.add('abc');
    //第二次监听
    conroller.stream.listen((event){
       print('Data2 is $event')
    });
     //给数据流添加数据
    controller.sink.add('123');
}

创建 Stream 实例

  • StreamController 类
    • sink
    • stream
  • Stream 类
    • Stream.fromFuture()
    • Stream.fromFutures()
    • Stream.fromIterable()
    • Stream.periodic()

image

Stream.fromFuture

Future<String> getData(){
    return Future.delayed(Duration(seconds:2),(){
        return '当前时间 ${DateTime.now()}';
    })
}

main(){
    Stream.fromFuture(getData()).listen((event){
        print('Stream.fromFuture: $event');
    }).onDone((){
        print('Stream.fromFuture done');
    })
}

Stream.fromFutures

Future<String> getData(){
    return Future.delayed(Duration(seconds:2),(){
        return '当前时间 ${DateTime.now()}';
    })
}

main(){
    var data = [getData(),getData()];
    Stream.fromFutures(data).listen((event){
        print('Stream.fromFuture: $event');
    }).onDone((){
        print('Stream.fromFuture done');
    })
}

Stream.fromIterable

Future<String> getData(){
    return Future.delayed(Duration(seconds:2),(){
        return '当前时间 ${DateTime.now()}';
    })
}

main(){
    var data = [1,2,'hello',true,null];
    Stream.fromIterable(data).listen((event){
        print('Stream.fromFuture: $event');
    }).onDone((){
        print('Stream.fromFuture done');
    })
}

Stream.periodic

main(){
    Duration interval = Duration(seconds:1);
    Stream<int> stream = Stream<int>.periodic(interval);
    //如果不设置第二个参数 默认返回null
    stream.listen((event){
        print('Stream.periodic:$event');
    }).onDone((){
        print('Stream.periodic done');
    });
}



main(){
    Duration interval = Duration(seconds:1);
    Stream<int> stream = Stream<int>.periodic(interval,(data)=>data);
    //如果设置第二个参数 默认返回具体数据
    stream.take(5).listen((event){//只拉五条数据
        print('Stream.periodic:$event');
    }).onDone((){
        print('Stream.periodic done');
    });
}

操作 Stream

  • take()|takeWhile()
  • where()
  • distinct()
  • skip()|skipWhile()
  • map() //跟 js 的 map 一样
  • toSet() |toList() |toString()
  • length |first|last take
main(){
    Duration interval = Duration(seconds:1);
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data);
    streamData.take(5).listen((event){
        print('Stream.periodic-> $event');
    }).onDone((){
        print('Stream.periodic-> done 结束');
    });
}

takeWhile

main(){
    Duration interval = Duration(seconds:1);
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data);
    streamData.takeWhile((element){
        print('Stream.periodic.takeWhile-> $element');
        return element<=3;
    }).listen((event){
        print('Stream.periodic-> $event');
    }).onDone((){
        print('Stream.periodic->done 结束')
    });
}


where

main(){
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data);
    streamData.takeWhile((element){
        print('takeWhile->$element');
        return element <= 5;
    }).where((data){
        print('where-> $data');
        return data %2 ==0;//返回偶数
    }).listen((event){
        print('--$event');
    }).onDone((){
        print('onDone 结束');
    })


}

distinct

main(){
    var data = [1,2,'a','a',true,true];
    Stream.fromIterable(data).distinct()//去掉与前一个相同的数据
    .listen((event){
        print('Stream.fromIterable->$event');
    }).onDone(()=>print('Stream.fromIterable->done结束'));
}

skip

main(){
    Duration interval = Duration(seconds:1);
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data);
    streamData.takeWhile((element){
        print('takeWhile:$element');
        return element <=6;
    }).skip(2).listen((event){
        print('-- $vent');
    }).onDone((){
        print('onDone 结束');
    });


}





map

main(){
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data+1);
    streamData.takeWhile((element){
        return element<=3;
    }).map((event){
        print('map-> $event  ->${event*100}');
        return event * 100;
    }).listen((event){
        print('listen->$event');
    }).onDone((){
        print('Done 结束');
    });

}


expand

main(){
    Stream<int> streamData = Stream<int>.periodic(interval,(data)=>data+1);
    streamData.takeWhile((element){
        return element<=3;
    }).expand((element){
        print('map-> $element->${element*100}');
        return [element,element*10,element*100];
    }).listen((event){
        print('listen->$event');
    }).onDone((){
        print('Done 结束');
    });

}

image

image

image

image

image

Last Updated:
Contributors: 刘荣杰