Dart开发学习.md

429 阅读11分钟

2020.02.25

因为公司业务需求,决定用Flutter进行开发,再此之前要先学习Dart语言。

搭建Dart环境

Dart介绍:

Dart是由谷歌开发的计算机编程语言,它可以被用于web、服务器、移动应用 和物联网等领域的开发。

Dart诞生于2011年,号称要取代JavaScript。但是过去的几年中一直不温不火。直到Flutter的出现现在被人们重新重视。

要学Flutter的话我们必须首先得会Dart。

官网:https://dart.dev/

Dart环境搭建:

要在我们本地开发Dart程序的话首先需要安装Dart Sdk

官方文档:https://dart.dev/get-dart

windows(推荐):

http://www.gekorm.com/dart-windows/

mac:

如果mac电脑没有安装brew这个工具首先第一步需要安装它: https://brew.sh/

brew tap dart-lang/dart

brew install dart

安装比较慢

Dart 开发工具

Dart的开发工具有很多: IntelliJ IDEA 、 WebStorm、 Atom、Vscode

这里我们主要给大家讲解的是如果在Vscode中配置Dart

  1. 找到vscode插件安装dart;
  2. 找到vscode插件安装code runner,Code Runner可以运行我们的文件.

Dart的变量 常量 命名规则

1. Dart 变量

dart是一个强大的脚本类语言,可以不预先定义变量类型 ,自动会类型推倒

dart中定义变量可以通过var关键字可以通过类型来申明变量

如:

var str='this is var';

String str='this is var';

int str=123;

注意: var 后就不要写类型 , 写了类型 不要var 两者都写 var a int = 5; 报错

2. Dart 常量:

final 和 const修饰符

const值不变 一开始就得赋值
final 可以开始不赋值 只能赋一次 ; 而final不仅有const的编译时常量的特性,最重要的它是运行时常量,并且final是惰性初始化,即在运行时第一次使用前才初始化


永远不改量的量,请使用final或const修饰它,而不是使用var或其他变量类型。


final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere

3. Dart的命名规则

  1.变量名称必须由数字、字母、下划线和美元符($)组成。

  2.注意:标识符开头不能是数字

  3.标识符不能是保留字和关键字。   

  4.变量的名字是区分大小写的如: age和Age是不同的变量。在实际的运用中,也建议,不要用一个单词大小写区分两个变量。

  5、标识符(变量名称)一定要见名思意 :变量名称建议用名词,方法名称建议用动词  

数据类型

1. Dart中的数据类型

常用数据类型

  Numbers(数值):
      int
      double
  Strings(字符串)
      String
  Booleans(布尔)
      bool
  List(数组)
      在Dart中,数组是列表对象,所以大多数人只是称它们为列表
  Maps(字典)
      通常来说,Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次

项目中用不到的数据类型 (用不到)

  1. Runes 
    Rune是UTF-32编码的字符串。它可以通过文字转换成符号表情或者代表特定的文字。

    main() {
      var clapping = '\u{1f44f}';
      print(clapping);
      print(clapping.codeUnits);
      print(clapping.runes.toList());
    
      Runes input = new Runes(
          '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
      print(new String.fromCharCodes(input));
    }

    
  2. Symbols
    Symbol对象表示在Dart程序中声明的运算符或标识符。您可能永远不需要使用符号,但它们对于按名称引用标识符的API非常有用,因为缩小会更改标识符名称而不会更改标识符符号。要获取标识符的符号,请使用符号文字,它只是#后跟标识符:


    在 Dart 中符号用 # 开头来表示,入门阶段不需要了解这东西,可能永远也用不上。
    
    http://dart.goodev.org/guides/libraries/library-tour#dartmirrors---reflection

字符串类型

  1. 字符串定义的几种方式
var str = 'this is str'; //单引号或者双引号

String str1 = 'this is String'; //变量类型:String (字符串类型)

String str1 = '''this is String1,
this is String2,

this is String3
''';//引用三个引号定义类型,多行显示

  1. 字符串的拼接
String str1='你好';
String str2='Dart';
print("$str1 $str2");//你好 Dart (最好用这种吧)
print(str1+' '+str2);//你好 Dart (和js一样)

数值类型

  1. int 必须是整型
  2. double 既可以是整型 也可是浮点型(如果double = 12;返回结果是12.0)
  3. 运算符 + - * / %

布尔类型

  1. bool 值true/false
  2. 条件判断语句
var a=123;
var b='123';
if(a==b){ 
    print('a=b');
}else{
    print('a!=b');
}
//在js中,123=='123',但是在dart中,不等
//返回结果a!=b

List(数组/集合)类型

  1. 第一种定义List的方式
var l1=['aaa','bbbb','cccc'];
print(l1.length);   //3
print(l1[1]);       //bbbb
  1. 第二种定义List的方式
var li = new List();
li.add('张三');
  1. 定义List指定类型
var l3=new List<String>();

l3.add('张三');

Maps(字典)类型

类似于js中的json

  1. 第一种定义 Maps的方式
var person={
  "name":"张三",
  "age":20,
  "work":["程序员","送外卖"]
};
print(person);
print(person["name"]);

  1. 第二种定义 Maps的方式
var p=new Map();
 
p["name"]="李四";
p["age"]=22;
p["work"]=["程序员","送外卖"];
print(p);

print(p["age"]);

类型判断

is 关键词来判断类型

var str=123;
if(str is String){
    print('是string类型');
}else if(str is int){
    print('int');
}else{
    print('其他类型');
}

2. 运算符

3. 算术运算符

  +    -    *    /     ~/ (取整)     %(取余)

4. 关系运算符

  ==    !=   >    <    >=    <=

5. 逻辑运算符

    !  &&   ||
  1. ! 取反
  2. &&并且:全部为true的话值为true 否则值为false
  3. ||或者:全为false的话值为false 否则值为true

6. 赋值运算符

 基础赋值运算符   =   ??=
 复合赋值运算符   +=  -=  *=   /=   %=  ~/=
 自增 ++ 自减 --
  1. b??=23; 表示如果b为空的话把 23赋值给b
int b;
b??=23;
print(b);//23
  1. var a = 12 ; a+=10; //表示a=a+10

  2. 自增 ++ ,自减 --

在赋值运算里面 如果++ -- 写在前面 这时候先运算 再赋值,

如果++ --写在后面 先赋值后运行运算

var a=10;
var b=a++;
print(a);  //11
print(b);  //10

var a=10;
var b=++a;
print(a);  //11
print(b);  //11

7. 条件表达式

  1. if else
  2. switch case
  3. 三目运算符
bool flag=false;
String c=flag?'我是true':'我是false';
print(c);
  1. ??运算符
//如果a是空,则b等于10 
var a=22;
var b= a ?? 10; 

print(b);//返回结果22


var a;
var b= a ?? 10; 

print(b);//返回结果10

8. Dart类型转换

  1. Number与String类型之间的转换
    • Number类型转换成String类型 toString()
    • String类型转成Number类型 int.parse()double.parse()
  2. 其他类型转换成Booleans类型
    • isEmpty:判断字符串是否为空
    • ==
    • ==null
    • isNaN
    var myNum=0/0;
    if(myNum.isNaN){
      print('NaN'); //NaN
    }
    

循环语句

1. for循环

二维数组

for(var i=0;i<list.length;i++){
    print(list[i]["cate"]);
    print('-------------');
    for(var j=0;j<list[i]["news"].length;j++){
        print(list[i]["news"][j]["title"]);
    }
}

2. while、do...while

  1. while(表达式/循环条件){}


int i=1;
var sum=0;
while(i<=100){
   sum+=i;
   i++;
}
print(sum);
  1. do{语句/循环体}while(表达式/循环条件);
int i=1;
var sum=0;
do{
   sum+=i;
   i++;
}while(i<=100);
print(sum);

第一次循环条件不成立的情况下有区别,注意死循环。

3. break语句功能

跳出当前循环,只能向外跳出一层

  1、在switch语句中使流程跳出switch结构。
  2、在循环语句中使流程跳出当前循环,遇到break 循环终止,后面代码也不会执行
  
  强调:
  1、如果在循环中已经执行了break语句,就不会执行循环体中位于break后的语句。
  2、在多层循环中,一个break语句只能向外跳出一层

break可以用在switch case中 也可以用在 for 循环和 while循环中

4. continue语句的功能

跳过当前循环体 然后循环还会继续执行

【注】只能在循环语句中使用,使本次循环结束,即跳过循环体重下面尚未执行的语句,接着进行下次的是否执行循环的判断。

continue可以用在for循环以及 while循环中,但是不建议用在while循环中,不小心容易死循环

List

List里面常用的属性和方法:

List myList=['香蕉','苹果','西瓜'];

new List()

常用属性:
    length          长度
    reversed        翻转            //(3,2,1) myList.reversed.toList() //[3,2,1]
    isEmpty         是否为空
    isNotEmpty      是否不为空
常用方法:  
    add         增加
    addAll      拼接数组            //类似js:push
    indexOf     查找  传入具体值    //indexOf查找数据 查找不到返回-1  查找到返回索引值
    remove      删除  传入具体值    //类似js:delete
    removeAt    删除  传入索引值   
    fillRange   修改                //myList.fillRange(startIndex,endIndex,value);
    insert(index,value);            指定位置插入    
    insertAll(index,list)           指定位置插入List
    toList()    其他类型转换成List  
    join()      List转换成字符串    //myList.join(',')
    split()     字符串转化成List    //str.split('-')
    forEach   
    map
    where
    any
    every

Set

  • 用它最主要的功能就是去除数组重复内容
  • Set是没有顺序且不能重复的集合,所以不能通过索引去获取值
var s = new Set();
s.add(1);
s.add(2);
print(s);//{1,2}
s.toList()//[1,2]

s.addAll(myList) //去重

Map

new Map()

Map p{"name":"张三"} 映射(Maps)是无序的键值对:

常用属性:
    keys            获取所有的key值
    values          获取所有的value值
    isEmpty         是否为空
    isNotEmpty      是否不为空
常用方法:
    remove(key)     删除指定key的数据
    addAll({...})   合并映射  给映射内增加属性
    containsValue   查看映射内的值  返回true/false
    forEach   
    map
    where
    any
    every

用于List和Map的遍历循环、查找的方法

  • for
  • for in
  • forEarch
  • map
  • where (条件判断)
  • any (返回bool类型:只要集合里有一个满足条件的就返回true)
  • every (每一个都要满足条件,返回true,否则返回false)

2020.02.26

函数

1. 方法的定义、变量、作用域

内置方法/函数:

  print();

自定义方法:

  自定义方法的基本格式:

  返回类型  方法名称(参数1,参数2,...){
    方法体
    return 返回值;
  }
void printInfo(){
  print('我是一个自定义方法');
}
int getNum(){
  var myNum=123;
  return myNum;
}

String printUserInfo(){
  return 'this is str';
}

List getList(){
  return ['111','2222','333'];
}

void main(){
    int sumNum(n){
        var sum = 0;
        for(var i=0;i<=n;i++){
          sum+=i;
        }
        return sum;
      }
    
      var n = sumNum(10);
    
      print(n);
}
  • 方法的作用域
void xxx(){

      aaa(){

          print(getList());
          print('aaa');
      }
      aaa();
  }

  aaa();  错误写法 

  xxx();  //调用方法

2. 方法传参 、默认参数、可选参数、命名参数 、方法作为参数

  1. 定义一个方法 求1到这个数的所有数的和 60 1+2+3+。。。+60(方法见上)
  2. 定义一个方法然后打印用户信息
String printUserInfo(String username,int age){  //行参
    return "姓名:$username---年龄:$age";
}
print(printUserInfo('张三',20)); //实参
  1. 定义一个带可选参数的方法 String printUserInfo(String username,[int age]){}
  2. 定义一个带默认参数的方法 String printUserInfo(String username,[String sex='男',int age]){}
  3. 定义一个命名参数的方法
String printUserInfo(String username,{int age,String sex='男'}){  //行参
      if(age!=null){
        return "姓名:$username---性别:$sex--年龄:$age";
      }
      return "姓名:$username---性别:$sex--年龄保密";
  }
 print(printUserInfo('张三',age:20,sex:'未知'));
  1. 实现一个 把方法当做参数的方法
//方法
fn1(){
print('fn1');
}

//方法
fn2(fn){

fn();
}

//调用fn2这个方法 把fn1这个方法当做参数传入
fn2(fn1);

3. 箭头函数、函数的相互调用

  1. 剪头函数 list.map((v)=>v>2?v*2:v);

  2. 函数的相互调用

    • 定义一个方法isEvenNumber来判断一个数是否是偶数
    bool isEvenNumber(int n){
        return n%2==0?true:false;
    }
    printNum(int n){
        for(var i=1;i<=n;i++){
            if(isEvenNumber(i)){
              print(i);
            }
        }
    }
    
    printNum(10);

4. 匿名方法、自执行方法、方法的递归

  1. 匿名方法
  var printNum=(int n){

    print(n+2);
  };

  printNum(12);
  1. 自执行方法(不需要调用就可以直接运行)
    ((int n){
      print(n);
      print('我是自执行方法');
    })(12);
  1. 方法的递归(判断什么时候结束循环,不然会进入死循环)
    • 通过方法的递归 求1-100的和
    var sum=0;
    fn(int n){

        sum+=n;

        if(n==0){
          return;
        }
        fn(n-1);
    }

    fn(100);
    print(sum);

5. 闭包

1、全局变量特点:    全局变量常驻内存、全局变量污染全局
2、局部变量的特点:  不常驻内存会被垃圾机制回收、不会污染全局  

想实现的功能:

    1.常驻内存        
    2.不污染全局   

      产生了闭包,闭包可以解决这个问题.....  

      闭包: 函数嵌套函数, 内部函数会调用外部函数的变量或参数, 变量或参数不会被系统回收(不会释放内存)

      闭包的写法: 函数嵌套函数,并return 里面的函数,这样就形成了闭包。
    fn(){
        var a=123;  /*不会污染全局   常驻内存*/
        return(){			
          a++;			
          print(a);
        };        
      }     
      var b=fn();	
      b();
      b();
      b();

面向对象

面向对象编程(OOP)的三个基本特征是:封装继承多态

  封装:封装是对象和类概念的主要特性。封装,把客观事物封装成抽象的类,
        并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则隐藏。
            
  继承:面向对象编程 (OOP)语言的一个主要功能就是“继承”。
       继承是指这样一种能力:它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
        
  多态:允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。

Dart所有的东西都是对象,所有的对象都继承自Object类。

Dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是Object的子类。

一个类通常由属性方法组成。

List list=new List();
list.isEmpty;
list.add('香蕉');

Map m=new Map();
m["username"]="张三";
m.addAll({"age":20});
m.isEmpty;

Object a=123;
Object v=true;
print(a);
print(v);

封装

1. 创建类使用类

Dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是Object的子类

class Person{ //定义类名首字母大写
    String name = '张三';
    int age = 23;
    
    void getInfo(){
        print("${this.name}----${this.age}");
    }
    void setInfo(int age){
        this.age = age;
    }
}
void main(){
    //实例化
    var p = new Person();
    print(p.name);//张三
    p.getInfo();//张三----23

    p.setInfo(18);
    p.getInfo();//张三----18
}

2. 自定义类的构造函数

自定义类的默认构造函数

class Person{
  String name;
  int age; 
  //默认构造函数的简写
  Person(this.name,this.age);
  
  //Person(String name,int age){
  //  print('这是构造函数里面的内容  这个方法在实例化的时候触发');
  //  this.name=name;
  //  this.age=age;
  //}
  void printInfo(){   
    print("${this.name}----${this.age}");
  }
}

void main(){
  Person p1=new Person('张三',20);
  p1.printInfo();

  Person p2=new Person('李四',25);
  p2.printInfo();
}

自定义类的命名构造函数

class Person{
    String name;
    int age; 
    //默认构造函数的简写
    Person(this.name,this.age);  //默认只能有一个
    
    Person.now(){
        print('我是命名构造函数'); //自定义可以多个
    }
    
    Person.time(){
         print('我是第二个命名构造函数'); 
    }
    
    void printInfo(){   
        print("${this.name}----${this.age}");
    }
}

void main(){
    // var d=new DateTime.now();   //实例化DateTime调用它的命名构造函数
    // print(d);
    
    Person p1=new Person('张三', 20);   //默认实例化类的时候调用的是 默认构造函数
    p1.printInfo(); 
    Person p2=new Person.now();   //命名构造函数
    Person p3=new Person.time(); 
}

3. 把类单独抽离成一个模块

在lib文件夹中,新建一个`Person.dart`,将`class Person`的内容写在此处;

通过`import 'lib/Person.dart';`引入,直接调用。

4. 私有方法和私有属性

Dart和其他面向对象语言不一样,Data中没有 public private protected这些访问修饰符合, 但是我们可以使用_把一个属性或者方法定义成私有。

class Animal{
  String _name;   //私有属性
  int age; 
  //默认构造函数的简写
  Animal(this._name,this.age);

  void printInfo(){   
    print("${this._name}----${this.age}");
  }

  String getName(){ 
    return this._name;
  } 
  void _run(){
    print('这是一个私有方法');
  }

  execRun(){
    this._run();  //类里面方法的相互调用
  }
}
import 'lib/Animal.dart';

void main(){
     Animal a=new Animal('小狗', 3);
     print(a.getName());
     a.execRun();   //间接的调用私有方法
}

5. 类中的getter和setter修饰符的用法

class Rect{
  num height;
  num width; 
  
  Rect(this.height,this.width);
  get area{
    return this.height*this.width;
  }
  set areaHeight(value){
    this.height=value;
  }
}

void main(){
  Rect r=new Rect(10,4);
  // print("面积:${r.area()}");   
  r.areaHeight=6;

  print(r.area);

}

6. 类中的初始化列表

Dart中我们也可以在构造函数体运行之前初始化实例变量

class Rect{

  int height;
  int width;
  Rect():height=2,width=10{
    
    print("${this.height}---${this.width}");
  }
  getArea(){
    return this.height*this.width;
  } 
}

void main(){
  Rect r=new Rect();
  print(r.getArea()); 
   
}

7. 类的静态成员和静态方法

  • Dart中的静态成员:
  1、使用`static` 关键字来实现类级别的变量和函数

  2、静态方法不能访问非静态成员,非静态方法可以访问静态成员
  • Dart中的静态方法
class Person {
  static String name = '张三';
  int age=20;
  
  static void show() {
    print(name);
  }
  void printInfo(){  /*非静态方法可以访问静态成员以及非静态成员*/
      // print(name);  //访问静态属性
      // print(this.age);  //访问非静态属性
      show();   //调用静态方法
  }
  static void printUserInfo(){//静态方法
        print(name);   //静态属性
        show();        //静态方法
        //print(this.age);     //静态方法没法访问非静态的属性
        // this.printInfo();   //静态方法没法访问非静态的方法
        // printInfo();
  }
}

main(){
  // print(Person.name);
  // Person.show(); 
  // Person p=new Person();
  // p.printInfo(); 
  Person.printUserInfo(); //调用静态方法
}

8. 对象操作符

?     条件运算符 (了解)            
as    类型转换                       
is    类型判断                      
..    级联操作 (连缀)  (记住)
    Person p;p?.printInfo();
    (p1 as Person).printInfo();
    if(p is Person)
    Person p1=new Person('张三1', 20);
    //  p1.name='张三222';
    //  p1.age=40;
    //  p1.printInfo();
    
    p1..name="李四"
      ..age=30
      ..printInfo();

继承

类的继承

向对象的三大特性:封装 、继承、多态

Dart中的类的继承:

  1. 子类使用extends关键词来继承父类
  2. 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
  3. 子类能复写父类的方法 getter和setter

1. 简单继承

extends关键词的使用

子类通过使用extends关键词来继承父类。

//父类
class Person(){
    String name='张三';
    num age=20; 
    void printInfo() {
        print("${this.name}---${this.age}");  
    } 
}
//子类继承父类
class Web extends Person{
    
}
viod main(){
   Web w = new Web();
   w.printInfo();
}

supper关键词的使用

父类中有构造函数时,子类继承父类要用到supper关键词。

实例化自类给父类构造函数传参:

class Person(){
    String name;
    num age;
    Person(this.name,this.age);
    void printInfo() {
        print("${this.name}---${this.age}");  
    } 
}
//子类继承父类
//可以通过修复完善代码
class Web extends Person{ 
    String sex;
    Web(String name, num age,String sex) : super(name, age){
        this.sex = sex;
    };
    run(){ //子类中定义自己的方法
        print("${this.name}---${this.age}--${this.sex}");  
    }
}
main(){ 
  Web w=new Web('张三', 12,'男');
  w.printInfo();
  w.run();
}

实例化自类给命名构造函数传参:

2. 覆写父类的方法@override

class Person {
  String name;
  num age; 
  Person(this.name,this.age);
  void printInfo() {
    print("${this.name}---${this.age}");  
  }
  work(){
    print("${this.name}在工作...");
  }
}

class Web extends Person(){
    Web(String name, num age) : super(name, age);

    run(){
       print('run');
    }
    @override       //可以写也可以不写  建议在覆写父类方法的时候加上 @override
    void printInfo() {
        print("姓名:${this.name}---年龄:${this.age}"); 
    }
    
    @override
    work(){
        print("${this.name}的工作是写代码");
    }
  }
}

main(){ 
  Web w=new Web('李四',20);
  w.printInfo();
  w.work();
}

3.自类里面调用父类的方法super

class Person {
  String name;
  num age; 
  Person(this.name,this.age);
  work(){
    print("${this.name}在工作...");
  }
}

class Web extends Person{
  Web(String name, num age) : super(name, age);
  run(){
    print('run');
    super.work();  //自类调用父类的方法
  }
}

2020.02.27

抽象类

Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口:

  1、抽象类通过`abstract`关键字来定义

  2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。

  3、如果子类继承抽象类必须得实现里面的抽象方法

  4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。

  5、抽象类不能被实例化,只有继承它的子类可以

extends抽象类 和 implements的区别:

  1、如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类

  2、如果只是把抽象类当做标准的话我们就用implements实现抽象类

案例:定义一个Animal 类要求它的子类必须包含eat方法

1. abstract关键字来定义抽象类

abstract class Animal(){
    eat();   //抽象方法
    run();  //抽象方法  
    printInfo(){
        print('我是一个抽象类里面的普通方法');
    }
}

2. 子类继承抽象类必须得实现里面的抽象方法

父类Animal中的eat和run方法必须实现,如果不写全,会报错,可以使用修复完善

class Dog extends Animal(){
    @override
    eat() {
        print('小狗在吃骨头');
    }
    
    @override
    run() {
        print('小狗在跑');
    }  
}
main(){
    
}

单个引用

Dog d=new Dog();
d.eat();
d.run();

Cat c=new Cat();
c.eat();

多态引用

Animal d = new Dog();
d.eat();

Animal c=new Cat();
c.eat();

3. 把抽象类当做接口

和Java一样,dart也有接口,但是和Java还是有区别的。

首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。

同样使用`implements`关键字进行实现。

但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。

而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。

建议使用抽象类定义接口,建议文件分离。

定义一个DB库 支持 mysql mssql mongodb ,mysql mssql mongodb三个类里面都有同样的方法

/lib/Db.dart

abstract class Db{   //当做接口   接口:就是约定 、规范
    String uri;      //数据库的链接地址
    add(String data);
    save();
    delete();
}

/lib/Mysql.dart

import 'Db.dart';
class Mysql implements Db{
  @override
  String uri;
  
  Mysql(this.uri);//构造函数

  @override
  add(String data) {   
    print('这是mysql的add方法'+data);
  }

  @override
  delete() {   
    return null;
  }
  
  @override
  save() {   
    return null;
  }
}

/index.drat 接口引用

import 'lib/Mysql.dart';
main(){
    Mysql mysql=new Mysql('xxxxxx接口地址');
    mysql.add('添加的内容');
}

4. implements实现多个接口

abstract class A{
  String name;
  printA();
}

abstract class B{
  printB();
}

class C implements A,B{  
  @override
  String name;  
  @override
  printA() {
    print('printA');
  }
  @override
  printB() {
    return null;
  }
}
void main(){
  C c=new C();
  c.printA();
}

5. 使用mixins实现类似多继承的功能

mixins的中文意思是混入,就是在类中混入其他功能。

在Dart中可以使用mixins实现类似多继承的功能

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:

1、作为mixins的类只能继承自Object,不能继承其他类
2、作为mixins的类不能有构造函数
3、一个类可以mixins多个mixins类
4、mixins绝不是继承,也不是接口,而是一种全新的特性
  1. 作为mixins的类只能继承自Object,不能继承其他类
class B {
  void printB(){
    print('B');
  }
}
class C with A,B{
  
}
  1. 作为mixins的类不能有构造函数
class A { 
    //A()  //报错 作为mixins的类不能有构造函数 
    String info ='this is A';
    void printA(){
        print('A');
    }
}

class B {
  void printB(){
    print('B');
  }
}

class C with A,B{
  
}

void main(){
  C c = new C();
  print(c.info);
  c.printA();
  c.printB();
  
  print(c is C);    //true
  print(c is A);    //true
  print(c is B);   //true
}
  1. 继承构造函数的的类
class Person {
  String name;
  int age;
  Person(this.name,this.age);
  printInfo(){
    print('这是一个Person类:${this.name}');
  }
}
class A {
    void run(){
        print('run-A');
    }
}

class B {
    void run(){
        print('run-B');
    }
}

class C extends Person with A,B {
  C(String name, int age) : super(name, age);
  
  printI(){
    print('run');
    super.printInfo();  //子类调用父类的方法
  }
  
}

main(){
    C c = new C('mavis',20);
    c.run(); //有同样方法,运行顺序with A,B,或者with B,A,会覆盖.
}

泛型

通俗理解:泛型就是解决 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

泛型方法

// T getData<T>(T value){
//     return value;
// }

getData<T>(T value){
    return value;
}

void main(){
    getData<String>('你好'); //指定类型是String 
    getData<int>(12);        //指定类型是int
}

泛型类

集合List 泛型类的用法

案例:要求List里面可以增加int类型的数据,也可以增加String类型的数据。但是每次调用增加的类型要统一。

class PrintClass<T>{
    List list = new List<T>();
    void add(T value){
        this.list.add(value);
    }
    void printInfo(){
        for(var i=0;i<=this.list.length;i++){
            print(this.list[i])
        }
    }
}

main(){
    PrintClass p = new PrintClass<int>();//设置int类型
    p.add(12);
    p.printInfo();
    
    或者
    PrintClass p = new PrintClass<String>();//设置String类型
    p.add('你好');
    p.printInfo();
}

泛型接口

实现数据缓存的功能:有文件缓存内存缓存

内存缓存和文件缓存按照接口约束实现。

1、定义一个泛型接口 约束实现它的子类必须有getByKey(key) 和 setByKey(key,value)

2、要求setByKey的时候的value的类型和实例化子类的时候指定的类型一致
abstract class Cache<T>{
  getByKey(String key);
  void setByKey(String key, T value);
}

class FlieCache<T> implements Cache<T>{
  @override
  getByKey(String key) {    
    return null;
  }

  @override
  void setByKey(String key, T value) {
    print("我是文件缓存 把key=${key}  value=${value}的数据写入到了文件中");
  }
}

class MemoryCache<T> implements Cache<T>{
  @override
  getByKey(String key) {   
    return null;
  }

  @override
  void setByKey(String key, T value) {
       print("我是内存缓存 把key=${key}  value=${value} -写入到了内存中");
  }
}
void main(){
    MemoryCache m=new MemoryCache<Map>();

    m.setByKey('index', {"name":"张三","age":20});
}

前面介绍Dart基础知识的时候基本上都是在一个文件里面编写Dart代码的,但实际开发中不可能这么写,模块化很重要,所以这就需要使用到库的概念。

在Dart中,库的使用时通过import关键字引入的。

library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。

Dart中的库主要有三种:

1、我们自定义的库     
      import 'lib/xxx.dart';
2、系统内置库       
      import 'dart:math';    
      import 'dart:io'; 
      import 'dart:convert';
3、Pub包管理系统中的库  
    https://pub.dev/packages
    https://pub.flutter-io.cn/packages
    https://pub.dartlang.org/flutter/

    (1) 需要在自己想项目根目录新建一个pubspec.yaml
    (2) 在pubspec.yaml文件 然后配置名称 、描述、依赖等信息
    (3) 然后运行 pub get 获取包下载到本地  
    (4) 项目中引入库 import 'package:http/http.dart' as http; 看文档使用

自定义库

import 'lib/Animal.dart';
main(){
  var a=new Animal('小黑狗', 20);
  print(a.getName());
}

前面内容有讲到。

系统内置库

  1. 导入系统内置库 math库
import 'dart:math';  
main(){
    print(min(12,23));

    print(max(12,25));
}
  1. 导入系统内置库实现请求数据httpClient,类似于js中的原生请求:
  • 异步请求,创建方法中使用async和await
  • 调用时,main也要用异步void main() async{}
import 'dart:io'; 
import 'dart:convert';

void main() async{
  var result = await getDataFromZhihuAPI();
  print(result);
}

//api接口: http://news-at.zhihu.com/api/3/stories/latest
getDataFromZhihuAPI() async{
    //1、创建HttpClient对象
    var httpClient = new HttpClient();  
    //2、创建Uri对象
    var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');
    //3、发起请求,等待请求
    var request = await httpClient.getUrl(uri);
    //4、关闭请求,等待响应
    var response = await request.close();
    //5、解码响应的内容
    return await response.transform(utf8.decoder).join();
}
  1. 关于asyncawait

    这两个关键字的使用只需要记住两点:

    • 只有async方法才能使用await关键字调用方法
    • 如果调用别的async方法必须使用await关键字
    async是让方法变成异步。
    
    await是等待异步方法执行完成。
    

导入Pub包管理系统中的库

pub包管理系统:

1、从下面网址找到要用的库

    https://pub.dev/packages
    https://pub.flutter-io.cn/packages
    https://pub.dartlang.org/flutter/

2、创建一个pubspec.yaml文件,内容如下

name: xxx
description: A new flutter module project.
dependencies:  
    http: ^0.12.0+2
    date_format: ^1.0.6

3、配置dependencies

4、运行pub get 获取远程库

5、看文档引入库使用

import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';

main() async{

    //1. 应用http库
    
    var url = "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1";

    // Await the http get response, then decode the json-formatted responce.
    var response = await http.get(url);
    if (response.statusCode == 200) {
      var jsonResponse = convert.jsonDecode(response.body);
      print(jsonResponse);
    } else {
      print("Request failed with status: ${response.statusCode}.");
    }

    //2. 应用date_format库
    print(formatDate(DateTime(1989, 2, 21), [yyyy, '*', mm, '*', dd]));
}

Dart库的重命名和Dart冲突解决

Dart库的重命名的冲突解决

  1. 当引入两个库中有相同名称标识符的时候,如果是java通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。如下例子所示:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

Element element1 = new Element();           // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.
import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib;

main(List<String> args) {
  Person p1=new Person('张三', 20);
  p1.printInfo();

  lib.Person p2=new lib.Person('李四', 20);
  p2.printInfo();
}

Dart的部分导入

如果只需要导入库的一部分,有两种模式:

模式一:只导入需要的部分,使用show关键字,如下例子所示:

import 'package:lib1/lib1.dart' show foo;

模式二:隐藏不需要的部分,使用hide关键字,如下例子所示:

import 'package:lib2/lib2.dart' hide foo;

延迟加载

也称为懒加载,可以在需要的时候再进行加载。

懒加载的最大好处是可以减少APP的启动时间。

懒加载使用deferred as关键字来指定,如下例子所示:

import 'package:deferred/hello.dart' deferred as hello;

当需要使用的时候,需要使用loadLibrary()方法来加载:

greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

初步学习完毕~