iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 5
3
Mobile Development

Flutter---Google推出的跨平台框架,Android、iOS一起搞定系列 第 5

【Flutter基礎概念與實作】 Day5–Dart Language(3)

今天是介紹Dart的最後一天了,來學如何定義class(類別)以及使用async(非同步)吧。

Class

物件跟類別的概念在這邊就不多解釋了,今天主要以例子來做介紹。
並且會簡單提一下Mixin的用法。

首先用實作會使用到的Youtube影片來當作範例。


void main(){
    var V = new Video('Dart Tutorial', 'Happy coding', '2019/9/14', 'https://123', 'https://456');
    print(V.title);
}
class Video {
    String title; //標題
    String description; //影片資訊
    String publishTime; //上傳時間
    String thumbnail; //縮圖網址
    String url; //影片網址
    
    Video(String title, String description, String publishTime, String thumbnail, String url) {
        this.title = title;
        this.description = description;
        this.publishTime = publishTime;
        this.thumbnail = thumbnail;
        this.url = url;
    }
}

這裡我們定義了一個Vidoe類別,裡面有幾個屬性用來描述影片並且擁有一個建構子(Constructor)當new物件時給予值。
這是基本的定義方法,比較特別的是Flutter只能有一個Unnamed Constructor,而不是像Java具有多載的特性可以定義擁有相同名字的建構子。但Flutter擁有易讀性更高的Name Constructor,來看下面的例子吧。

void main() {
  var video1 = new Video('Dart Tutorial', 'Happy coding', '2019/9/14',
      'https://123', 'https://456');
  print(video1.title); //Output: Dart Tutorial
  
  var video2 = new Video.onlyUrl("https://123.456");
  print(video2.url); //Output: https://123.456
  
  var video3 = new Video.onlyTitle("Only title");
  print(video3.title); //Output: Only title
}

class Video {
  String _title; //標題
  String _description; //影片資訊
  String _publishTime; //上傳時間
  String _thumbnail; //縮圖網址
  String _url; //影片網址

  Video(this._title, this._description, this._publishTime, this._thumbnail, this._url);
  
  Video.onlyUrl(this._url);
  
  Video.onlyTitle(String title){
      this._title = title;
  }
  
  //getter
  String get title => this._title;
  String get url => this._url;
  
  //setter
  set title(String title) {
      this._title = title;
  }
}

這邊多定義了兩個Name ConstructoronlyUrlonlyTitle,這樣一來就可以依照不同的情況來做使用。

眼尖的你應該有發現原本的建構子Video從7行長縮減成1行,這是Dart提供的簡寫語法,可以少打很多字喔。

另外要提的是屬性名稱前面的_,在Dart並沒有private、public、public這些關鍵字,當你要使function或是變數為private時只需要在名稱前加上_即可,這樣能防止變數被其他地方存取。


Dart的class也有繼承的功能,在定義class時在後面使用extends關鍵字,但需要注意的是Dart跟Java一樣只能繼承一個父類,。

class People {
    String name;
    int age;
    
    People(this.name, this.age);
    String introduce() => "I'm $name. Nice to meet you.";
}

class Boy extends People {
    Boy(String name, int age): super(name, age);
}

void main() {
    var Jack = new Boy('Jack', 5);
    print(Jack.introduce());
}

Dart還有Mixin的機制,能讓你的class使用其他class的功能,卻不用成為它的子類。而且能一次Mixin多個class,使用起來比繼承更有彈性。
使用Mixin的關鍵字為with

mixin Android {
    String android() => "I'm android developer.";
}

mixin IOS {
    String ios() => "I'm ios developer.";
}

class People {
    String name;
    int age;
    
    People(this.name, this.age);
    String introduce() => "I'm $name. Nice to meet you.";
}

class Flutter extends People with Android, IOS{
    Flutter(String name, int age): super(name, age);
}

void main() {
    var coder = new Flutter('Tracy', 23);
    print(coder.introduce());
    print(coder.android());
    print(coder.ios());
}

這裡我們定義一個Flutterclass讓它繼承People並mixin新增的Android IOS這兩個mixin class。
如此一來我們實體化的物件coder就可以使用他們三個class的功能。


Async

Asynchronous(非同步)讓我們能夠不需等待一個所需時間較長的動作(寫入、讀取資料庫或是抓取網路資料)而讓整個程式卡住,而是用非同步的方式先讓其他工作執行當資料回來後我們再回頭處理。

之後的實作專案中,我們在呼叫Youtube API時也會使用非同步的方式和Server索取影片資訊,拿到資料後才顯示在螢幕上。

先來認識Dart跟非同步相關的三個名詞,Future、async、await
Future:Future是一個class,他用來表示非同步操作的結果,並且擁有兩個狀態,完成(completed)與未完成(uncompleted)
async:async是一個關鍵字,是用於區分function是同步或是不同步,使用方法是在定義function時加上async
await:只能在非同步function中才能使用await,用來等待非同步工作的完成結果,使用await有助於程式碼的易讀性


import 'dart:async';

Future<void> introduction(){
  return Future.delayed(
     Duration(seconds: 2), () => print("Dart tutorial"));
}

void main() {
  print("Before introduction");
  introduction();
  print("After introduction");
}

在這個範例中我們使用Future.delayed來模擬非同步工作的情形,等待二秒後會輸出"Dart tutorial",回傳值為Future這是因為完成後它並不會有值回傳所以type是void。

輸出的順序為"Before intorduction" -> "After intorduction" -> "Dart tutorial"
確實執行introduction()不會讓程式卡住而是先往下執行,當完成後才又回去處理。


import 'dart:async';

Future<String> introduction(){
  return Future<String>.delayed(
     Duration(seconds: 2), () => "Dart tutorial");
}

void main() async{
  print("Before introduction");
  print(await introduction());
  print("After introduction");
}

那麼使用await的效果會是如何呢?
現在我們把introduction的回傳值改為Future<String>,表示工作完成後會回傳的type為String
main()後頭加上async關鍵字並使用await來呼叫introduction
這次的輸出結果變成"Before intorduction" -> "Dart tutorial" -> "After intorduction"

證明使用await,程式會等待introduction執行完成取得回傳值才繼續執行下去。


今日總結

Dart的「mixin」其實還有許多其他的用法,例如可以指定特定class才能mixin的關鍵字on,想要了解更清楚的知識可以看這篇medium的文章他說明的非常清楚。

另外就是如果你想寫的App常需要呼叫網路API或是資料庫讀寫,那麼非同步的概念一定要建立。

今天只有稍微提到非同步的概念,有興趣的人可以看看Dart官方非同步教學並試著做裡面的題目,對如何在Dart裡使用async會有更深的認識。

Dart的教學就這樣快速帶過,明天開始就正式進入Flutter的世界,會從熟悉Flutter的檔案架構開始、以及widget和library的介紹,最後就來實做一個具有Google登入功能以及串接Youtube Api的App。


上一篇
【Flutter基礎概念與實作】 Day4–Dart Language(2)
下一篇
【Flutter基礎概念與實作】 Day6–Flutter Hello World!
系列文
Flutter---Google推出的跨平台框架,Android、iOS一起搞定30

2 則留言

1
imakou
iT邦新手 5 級 ‧ 2019-10-20 14:26:38

您好,
文章實在很棒。
不過我有點不太理解(原諒我沒有很強的OOP還有C語言背景)
請問

Future<void> introduction()

這段可以稍微解釋嗎?我尤其不是很懂這段

Future<void>

這應該是Dart的基本語法概念我不知道。

謝謝

看更多先前的回應...收起先前的回應...
imakou iT邦新手 5 級 ‧ 2019-10-20 14:27:21 檢舉
Future<viod>

這段,上面留言顯示不完全?

void的意思是函式執行完後不會有回傳值
Future<void>意思是當非同步事件完成後,不會有回傳值

以我上面的範例來說:

Future.delayed(
     Duration(seconds: 2), () => print("Dart tutorial"));

表示當延遲兩秒的工作完成後,會在Console顯示"Dart tutorial",並不會有回傳值,所以使用Future<void>

Future<String>.delayed(
     Duration(seconds: 2), () => "Dart tutorial");

表示當延遲兩秒的工作完成後,會「回傳」"Dart tutorial"給呼叫它的人,所以要使用Future<String>讓呼叫他的人知道回傳的型態。

希望這樣的解釋對你有幫助,如果還是不懂可以再發問~

imakou iT邦新手 5 級 ‧ 2019-10-20 16:02:07 檢舉

明白。
所以

Future<void> introduction()

就是定義一個名為introduction的func
但是因為要回傳一個Future類別所以就在 這個func前面下了

Future<void>

指名回傳的類型為Future

又,下面的例子就是,回傳一個是String值的Future的類別
是否解釋正確呢?

Future<String> introduction(){
  return Future<String>.delayed(
     Duration(seconds: 2), () => "Dart tutorial");
}

謝謝哦~~

對 沒錯
再舉一個Day16的例子

Future<MovieList> fetchPopularMovieList({String region = 'TW'}) async {
    final response = await _client
        .get("$_baseUrl/popular?api_key=$_apiKey&page=1&region=$region");
    if (response.statusCode == 200) {
      return MovieList.fromJson(json.decode(response.body));
    } else {
      throw Exception('Failed to get popular movie list.');
    }
}

因為MovieList.fromJson(json.decode(response.body));會回傳「MovieList」型態的物件。所以在fetchPopularMovieList我們會需要回傳的是Future<MovieList>,表示當非同步事件處理完後回傳的物件型態是「MovieList」。

b8201032 iT邦新手 5 級 ‧ 2020-02-03 11:57:14 檢舉

拜讀 這裡futter dart 文章
寫得實在太好,省我好多學習時間
謝謝哦

0
layer86109
iT邦新手 5 級 ‧ 2020-11-24 09:41:06

請問這段程式碼主要是什麼意思,沒有理解到

//getter
String get title => this._title;
String get url => this._url;

//setter
set title(String title) {
this._title = title;
}

由於我們class內變數僅能在class中存取,因此我們透過get和set作為媒介讓外部也能存取及修改變數

謝謝你~

我要留言

立即登入留言