首頁>技術>

原文連結:https://zhuanlan.zhihu.com/p/90836859

本文針對 Flutter 的技術特性,做了一些略全面的入門級的介紹,如果你聽說過Flutter,想去了解它,但是又不想去翻厚厚的API,那麼本文就是為你準備的。

隨著純客戶端到Hybrid技術,到RN&Weex,再到現在的Flutter技術,客戶端實現技術不斷前進。 在之前的一個APP專案中,因為歷史原因當時選擇了weex,隨著使用的不斷深入,我們逐漸發現了weex的渲染效能問題已經成為一個隱患和瓶頸。 而Flutter技術的不斷成熟和流行,Flutter的良好的跨平臺性和高效能優點,不斷吸引著我們。

(本文包含以下內容,閱讀完需要約18分鐘)

1.Flutter是啥玩意兒?2.移動端跨平臺技術對比2.1 H5+原生APP2.2 RN&Weex2.3 Flutter3.Dart語言4.環境配置5.Hello World5.1 建立專案5.2 專案結構5.3 啟動模擬器5.4 啟動專案APP5.5 簡化版的Hello World5.6 給頁面加上狀態5.7 小結一下6.路由6.1 單個頁面的跳轉6.2 更多頁面跳轉使用路由表6.3 路由傳參7.widget7.1 Text7.2 Button7.3 Container7.4 Image8.佈局8.1 Row & Column & Center 行列軸佈局8.2 Align 角定位佈局8.3 Stack & Positioned 絕對定位8.4 Flex & Expanded 流式佈局9.動畫9.1 簡單動畫:淡入淡出9.2 複雜一些的動畫:放大縮小10.http請求10.1 HttpClient10.2 http10.3 Dio11.吐吐槽11.1 牆11.2 元件過度設計11.3 巢狀太多不適應11.4 佈局修改會導致巢狀關係修改11.5 Dart語言升級11.6 不能熱更新12.結語1.Flutter是啥玩意兒?

Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構建高品質的原生使用者介面。

具有跨平臺開發特性,支援IOS、Android、Web三端。熱過載特性大大提高了開發效率自繪UI引擎和編譯成原生程式碼的方式,使得系統的執行時的高效能成為了可能使用Dart語言,目前已經支援同時編譯成Web端程式碼,

到底值不值得跟進Flutter技術呢? 還是看下Flutter,Weex,ReactNative的搜尋指數對比,大概就知道這個行業趨勢了。

藍色是Flutter,可以看出上升勢頭非常強勁。苦逼的前端就是這樣,你不跟潮流,潮流就會把你拋棄。

2.移動端跨平臺技術對比

為啥會有Flutter這種東西? 他的原理是什麼? 他是怎麼做到高效能的? 要明白這些問題,我們不得不從幾種移動端跨平臺技術的對比講起。

2.1 H5+原生APP

技術門檻最低,接入速度最快,熱更新最方便的,自然就是H5方式。APP中提供一個Webview使用H5頁面的Http直連。APP和H5可以相互獨立開發,JS使用Bridge與原生進行資料通訊,顯示介面依賴Webview的瀏覽器渲染。 但是帶來的問題也很明顯,因為是需要遠端直連,那麼初次開啟H5頁面,會有瞬間的白屏,並且Webview本身會有至少幾十M的記憶體消耗。

當然,作為前端開發人員,在H5方式可以使用SPA單頁面、懶載入、離線H5等各種前端優化手段進行效能優化,以使得H5的表現更接近原生。但是首次的瞬間白屏和記憶體,Bridge的通訊效率低下,始終是被技術框架給侷限住了。

2.2 RN&Weex

由於H5的那些弊端,愛折騰的前端工程師,祭出了RN、Weex兩個大殺器, 使用原生去解析RN、Weex的顯示配置,顯示層、邏輯層都直接與原生資料通訊。 因為拋棄了瀏覽器,自然渲染效能、執行效能都提升了一大截。

但是,每次遇到顯示的變更,JS都還會通過Bridge和原生轉一道再做渲染的調整,所以Bridge就最後成為了效能的瓶頸。在實際專案中,特別是做一些大量複雜動畫處理的時候,由於渲染部分需要頻繁通訊,效能問題變得尤為突出。 有興趣的同學可以去看看BindingX,裡面有關於動畫中資料通訊效率低下導致動畫幀率低下的詳細說明。

2.3 Flutter

不得不佩服Google開發人員的想象力,為了達到極致效能,Flutter更前進了一步,Flutter程式碼編譯完成以後,直接就是原生程式碼,並且使用自繪UI引擎原生方式做渲染。 Flutter依賴一個Skia 2D圖形化引擎。Skia也是Android平臺和Chrome的底層渲染引擎,所以效能方面完全不用擔心。因為使用Dart做AOT編譯成原生,自然也比使用解釋性的JS在V8引擎中執行效能更快,並且因為去掉Bridge,沒有了繁瑣的資料通訊和互動,效能就更前進了一步。

3.Dart語言

學習Flutter,得先了解Dart。Dart語言曾經雄心勃勃的要替換Javascript, 但是釋出的時機正好遇到JS的飛速發展,於是就逐漸沉寂,直到配合Flutter的釋出,才又重新煥發了生機。

在最近2019年9月的一次Google開發者大會中,伴隨著Flutter1.9的釋出,目前的Dart也同時更新到了2.5版本, 提供了機器學習和對C跨平臺呼叫的能力。總體來說,Dart語法,對於前端同學,上手還是很容易的,風格很像。

關於Dart語法,請移步傳送門:https://dart.dev/samples

4.環境配置

無論學什麼新語言,首先都是環境配置。由於Flutter出自Google,所以有一定門檻,如果在公司內安裝,你還需要一個方便的代理切換工具, 比如:Proxifier 。

安裝教程,參照官網:https://flutter.dev/docs/get-started/install

Flutter支援多種編輯器如:Android Studio , XCode。 但是既然作為支援跨雙端的開發,個人還是推薦使用 VSCode。

VSCode安裝完成後,需要安裝Flutter外掛,和Dart外掛. 在擴充套件窗口裡,搜尋Flutter,和Dart,點選“Install”即可,非常方便。

如果安裝不上去,記得開啟下代理。

5.Hello World

作為一個偉大的程式設計師,第一行程式碼總是從Hello World開始。_

5.1 建立專案:

方法1:直接使用命令建立:

flutter create projectname

方法2:使用VSCode建立:

View -> Command Palette -> Flutter:New Project 即可

注意請先開啟代理,否則你的建立進度,會一直被卡住。

5.2 專案結構

將專案先拖入VSCode,看下目錄結構。自動建立完成的專案中,我們看到已經自帶了Android,IOS相關的執行環境。

入口主檔案是main.dart. 可以開啟來先熟悉下,暫時不了解沒關係,後面再講。

還有一個重要的檔案是pubspec.yaml ,是專案的配置檔案,這個後續也會做修改。

5.3 啟動模擬器

5.4 啟動專案APP

選中Main.dart, 點選Debug-> Start Debugging , 專案就會啟動除錯,並在模擬器裡執行。

5.5 簡化版的Hello World

講道理,Flutter一上來就用StatefulWidget做一個自增的Demo,其實是對新手不太友好。 我還是喜歡循序漸進,先刪掉那些複雜的自增邏輯,我們基於StatelessWidget 只做一個最簡單的靜態頁面顯示。(什麼是StatefulWidget 和StatelessWidget?後面會說)

main.dart

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: MyHomePage(), ); }}class MyHomePage extends StatelessWidget{ @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("我是Title"), ), body: Center( child: Text( 'Hello World', ) ) ); } }

在上面的程式碼中,可以清楚看到,最簡單的頁面的層級關係:

MaterialApp -> MyHomePage -> Scaffold -> body -> Center -> Text

Scaffold是啥?他是Flutter的頁面腳手架,你可以當HTML頁面一樣去理解,不同的是,他除了Body以外,還提供appBar頂部TitleBar、bottomNavigationBar底部導航欄等屬性。

顯示效果:

這是最簡單的頁面,沒有互動,只有顯示,但是實際業務場景中,是不太可能都是這種頁面的,頁面上的資料一般都是來自介面返回,然後再在頁面上進行動態的渲染。 此時,就需要使用使用帶狀態的StatefulWidget了

5.6 給頁面加上狀態

import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: MyHomePage(), ); }}class MyHomePage extends StatefulWidget{ @override MyHomePageState createState() => MyHomePageState();}class MyHomePageState extends State<MyHomePage>{ var msg="Hello World"; //msg預設文字 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("我是Title"), ), body: Center( child:Column( children:<Widget>[ Text(msg), //根據變數值,顯示文字 FlatButton( color: Colors.blue, textColor: Colors.white, //點選按鈕,修改msg的文字 onPressed: () { setState(() { this.msg="You Click ME"; }); }, child: Text( "Click ME", style: TextStyle(fontSize: 20.0), ), ) ] ) ) ); } }

執行效果:

上面最關鍵的一段程式碼就是這個:

onPressed: () { setState(() { this.msg="You Click ME"; }); },

相信寫過小程式的同學,對這個 setState 還是很眼熟的 _

5.7 小結一下

StatelessWidget:無狀態變更,UI靜態固化的Widget, 頁面渲染效能更高。 StatefulWidget:因狀態變更可以導致UI變更的的Widget,涉及到資料渲染場景,都使用StatefulWidget。

為啥要分兩個? StatelessWidget擁有的功能,StatefulWidget都有了啊?

答案只有一個:效能、效能、效能

在StatefulWidget裡,因為要維護狀態,他的生命週期比StatelessWidget更復雜,每次執行setState,都會觸發 window.scheduleFrame() 導致整個頁面的widget被重新整理,效能就會降低。

使用過小程式的同學在這點上應該有體會,在小程式的官方文件中,會強烈建議減少setData的使用頻率,以避免效能的下降。 只不過flutter更是激進,推出了StatelessWidget,並直接在該Widget裡砍掉了setState的使用。

頁面結構關係如下:

6.路由

實際的專案,是有多個不同的頁面的,頁面之間的跳轉,就要用到路由了。 我們增加一個list頁面,點選Home頁的“Click Me”按鈕,跳轉到列表頁list。

6.1 單個頁面的跳轉

增加list.dart

import 'package:flutter/material.dart';class ListPage extends StatelessWidget { @override Widget build(BuildContext context) { //定義列表widget的list List<Widget> list=<Widget>[]; //Demo資料定義 var data=[ {"id":1,"title":"測試資料AAA","subtitle":"ASDFASDFASDF"}, {"id":2,"title":"測試資料bbb","subtitle":"ASDFASDFASDF"}, {"id":3,"title":"測試資料ccc","subtitle":"ASDFASDFASDF"}, {"id":4,"title":"測試資料eee","subtitle":"ASDFASDFASDF"}, ]; //根據Demo資料,構造列表ListTile元件list for (var item in data) { print(item["title"]); list.add( ListTile( title: Text(item["title"],style: TextStyle(fontSize: 18.0) ), subtitle: Text(item["subtitle"]), leading: Icon( Icons.fastfood, color:Colors.orange ), trailing: Icon(Icons.keyboard_arrow_right) )); } //返回整個頁面 return Scaffold( appBar: AppBar( title: Text("List Page"), ), body: Center( child: ListView( children: list, ) ), ); }}

在main.dart增加list頁面的引入

import 'list.dart';

修改Home頁的按鈕事件,增加Navigator.push跳轉

FlatButton( color: Colors.blue,textColor: Colors.white, onPressed: () { Navigator.push(context, MaterialPageRoute(builder:(context) { return ListPage(); })); }, child: Text("Click ME",style: TextStyle(fontSize: 20.0) ), )

核心方法就是:Navigator.push(context,MaterialPageRoute)

跳轉示例:

6.2 更多頁面跳轉使用路由表

在MaterialApp中,有一個屬性是routes,我們可以對路由進行命名,這樣跳轉的時候,只需要使用對應的路由名字即可,如:Navigator.pushNamed(context, RouterName)。點選兩個不同的按鈕,分別跳轉到ListPage,和Page2去。

Main.dart修改一下如下:

import 'package:flutter/material.dart';import 'list.dart';import 'page2.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', //路由表定義 routes:{ "ListPage":(context)=> ListPage(), "Page2":(context)=> Page2(), }, home: MyHomePage(), ); }}class MyHomePage extends StatefulWidget{ @override MyHomePageState createState() => MyHomePageState();}class MyHomePageState extends State<MyHomePage>{ @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("我是Title"), ), body: Center( child:Column( children:<Widget>[ RaisedButton( child: Text("Clikc to ListPage" ), onPressed: () { //根據命名路由做跳轉 Navigator.pushNamed(context, "ListPage"); }, ), RaisedButton( child: Text("Click to Page2" ), onPressed: () { //根據命名路由做跳轉 Navigator.pushNamed(context, "Page2"); }, ) ] ) ) ); } }

示例:

當我們有了路由以後,就可以開始在一個專案裡用不同的頁面,去學習不同的功能了。

6.3 路由傳參

列表頁跳轉到詳情頁,需要路由傳參,這個在flutter體系裡,又是怎麼做的呢?

首先,在main.dart裡,增加詳情頁DedailPage的路由配置

//路由表定義 routes:{ "ListPage":(context)=> ListPage(), "Page2":(context)=> Page2(), "DetailPage":(context)=> DetailPage(), //增加詳情頁的路由配置 },

並修改ListPage裡ListTile的點選事件,增加路由跳轉傳參,這裡是將整個item資料物件傳遞

ListTile( title: Text(item["title"],style: TextStyle(fontSize: 18.0) ), subtitle: Text(item["subtitle"]), leading: Icon( Icons.fastfood, color:Colors.orange ), trailing: Icon(Icons.keyboard_arrow_right), onTap:(){ //點選的時候,進行路由跳轉傳參 Navigator.pushNamed(context, "DetailPage", arguments:item); }, )

詳情頁DetailPage裡,獲取傳參並顯示

import 'package:flutter/material.dart';class DetailPage extends StatelessWidget { @override Widget build(BuildContext context) { //獲取路由傳參 final Map args = ModalRoute.of(context).settings.arguments; return Scaffold( appBar: AppBar( title: Text("Detail Page"), ), body: new Column( children: <Widget>[ Text("我是Detail頁面"), Text("id:${args['id']}" ), Text("id:${args['title']}"), Text("id:${args['subtitle']}") ], ) ); }}

Demo效果:

7.widget

Flutter提供了很多預設的元件,而每個元件的都繼承自widget 。 在Flutter眼裡:一切都是widget。 這句看起來是不是很熟悉? 還記得在webpack裡,一切都是module嗎? 類似的還有java的一切都是物件。貌似任何一個技術,最後都是用哲學作為指導思想。

widget,作為視覺化的UI元件,包含了顯示UI、功能互動兩部分。大的widget,也可以由多個小的widget組合而成。

常用的widget元件:

7.1 Text

Demo:

Text( "Hello world", style: TextStyle( fontSize: 50, fontWeight: FontWeight.bold, color:Color(0xFF0000ff) ) ),

Text的樣式,來自另一個widget:TextStyle。 而TextStyle裡的color,又是另一個widget Color的例項。

如果用flutter的縮排的方法,看起來確實有點醜陋,習慣寫CSS的前端同學,可以看看下面的風格:

Text( "Hello world", style: TextStyle( fontSize: 50,fontWeight: FontWeight.bold,color:Color(0xFF0000ff) ) )

寫成一行,是不是就順眼多了?這算前端惡習嗎?_

7.2 Button

對於flutter來說,Button就提供了很多種,我們來看看他們的區別:

RaisedButton: 凸起的按鈕 FlatButton:扁平化按鈕 OutlineButton:帶邊框按鈕 IconButton:帶圖示按鈕

import 'package:flutter/material.dart';class ButtonPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Button Page"), ), body: Column( children: <Widget>[ RaisedButton( child: Text("我是 RaiseButton" ), onPressed: () {}, ), FlatButton( child: Text("我是 FlatButton" ), color: Colors.blue, onPressed: () {}, ), OutlineButton( child: Text("我是 OutlineButton" ), textColor: Colors.blue, onPressed: () {}, ), IconButton( icon: Icon(Icons.add), onPressed: () {}, ) ] ) ); }}

Demo:

專案中要用哪個,就各取所需吧~

7.3 Container

Container是非常常用的一個widget,他一般是用作一個容器。我們先來看看他的基礎屬性,順便可以想想他像HTML裡的啥?

基礎屬性:width,height,color,child

body: Center( child: Container(  color: Colors.blue,  width: 200,  height: 200,  child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)), ) )

Padding

我們也可以不設定寬高,用padding在內部撐開增加留白:

Container( color: Colors.blue, padding: EdgeInsets.all(30), child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)), )

Margin

我們還可以使用margin,在容器的外部撐開增加偏移量,

Container( color: Colors.blue, padding: EdgeInsets.all(30), margin: EdgeInsets.only(left: 150,top: 0,right: 0,bottom: 0), child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)), )

Transform

我們還可以給這個矩形,使用tansform做一些變化,比如,旋轉一個角度

Container( color: Colors.blue, padding: EdgeInsets.all(30), child: Text("Hello Container ",style:TextStyle(fontSize: 20,color: Colors.white)), transform: Matrix4.rotationZ(0.5) )

看到這裡,好多前端同學要說了,好熟悉啊。 對,他就是很像Html裡的一個東西:DIV,你確實可以對應的去加強理解。

7.4 Image

網路圖片載入

使用NetworkImage,可以做網路圖片的載入:

child:Image( image: NetworkImage("http://127.0.0.1/vhost/conf/img_echo.php?w=640&h=1319&src=https://mat1.gtimg.com/pingjs/ext2020/qqindex2018/dist/img/qq_logo_2x.png"), width: 200.0, )

本地圖片載入

載入本地圖片,就稍微複雜一些,首先要把圖片的路徑配置,加入到之前說過的pubspec.yaml配置檔案裡去:

載入本地圖片時使用AssetImage:

child:Image( image: AssetImage("assets/images/logo.png"), width: 200.0, ) 

也可以使用簡寫:

 Image.asset("assets/images/logo.png",width:200.0)

flutter提供的元件很多,這裡就不一一舉例說明,有興趣的還是建議大家去看API:https://api.flutter.dev/

8.佈局

我們已經了解了這麼多元件,那麼怎麼繪製一個完整的頁面呢? 這就到了頁面佈局的部分了。

8.1 Row & Column & Center 行列軸佈局

字面意義也很好理解,行佈局、列布局、居中佈局,這些佈局對於Flutter來說,也都是一個個的widget。

區別在於,row、column 是有多個children的widget, 而Center是隻有 1個child的 widget。

 Row( children:<Widget>[] )  Column( children:<Widget>[] )  Center( child:Text("Hello") )

8.2 Align 角定位佈局

我們常常在Container裡,需要顯示的內容在左上角,左下角,右上角,右下角。 在html時代,使用CSS可以很容易的實現,但是flutter裡,必須依賴Align 這個定位的Widget

右下角定位示例:

 child: Container(  color: Colors.blue,  width: 300,  height: 200,  child: Align(  alignment: Alignment.bottomRight,  child:Text("Hello Align ",style:TextStyle(fontSize: 20,color: Colors.white)), ) )

顯示效果:

Alignment提供了多種定位供選擇,還算是很貼心的。

8.3 Stack & Positioned 絕對定位

當然還有絕對定位的需求,這在css裡,使用position:absolute就搞定了,但是在flutter裡,需要藉助stack+ positioned兩個widget一起組合使用。

Stack: 支援元素堆疊 Positioned:支援絕對定位

child:Stack( children: <Widget>[ Image.network("http://127.0.0.1/vhost/conf/img_echo.php?w=640&h=1344&src=https://ossweb-img.qq.com/upload/adw/image/20191022/627bdf586e0de8a29d5a48b86700a790.jpeg"), Positioned( top: 20, right: 10, child:Image.asset("assets/images/logo.png",width:200.0) ) ], )

8.4 Flex & Expanded 流式佈局

Flex流式佈局作為前端同學都熟悉,之前講過的Row,Column,其實都是繼承自Flex,也屬於流式佈局。

如果軸向不確定,使用Flex,通過修改direction的值設定軸向 如果軸向已確定,使用Row,Column,佈局更簡潔,更有語義化

Flex測試頁:

class FlexPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flex Page"), ), body: Flex( direction: Axis.horizontal, children: <Widget>[ Container( width: 30, height: 100, color: Colors.blue, ), Expanded( flex: 1, child: Container( height: 100.0, color: Colors.red, ), ), Expanded( flex: 1, child: Container( height: 100.0, color: Colors.green, ), ), ], ), ); }}

示例中,軸向橫向排列,最左邊一個固定寬度的Container,右邊兩個Expanded,各自佔剩下的寬度的一半。

9.動畫

Flutter既然說了,一切都是Widget,包括動畫實現,也是一個Widget。 我們還是看一個示例

9.1 簡單動畫:淡入淡出:

使用flutter提供的現成的Widget:

import 'package:flutter/material.dart';class AnimatePage extends StatefulWidget { _AnimatePage createState()=> _AnimatePage();} class _AnimatePage extends State<AnimatePage> { bool _visible=true; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Animate Page"), ), body: Center( child: Column( children: <Widget>[ AnimatedOpacity( opacity: _visible ? 1.0:0.0, duration: Duration(milliseconds: 1000), child: Image.asset("assets/images/logo.png"), ), RaisedButton( child: Text("顯示隱藏"), onPressed: (){ setState(() { _visible=!_visible; }); }, ), ], ), ) ); }}

其中的AnimatedOpacity就是動畫透明度變化的的Widget,而被透明度控制變化的Image則是AnimatedOpacity的子元素。這個和以往前端寫動畫的方式,就完全不一樣了,需要改變一下思維方式。

Demo效果

9.2 複雜一些的動畫:放大縮小

當寫複雜一些動畫的時候,沒有對應的widget元件,就需要自己使用Animation,和AnimationController,以及Tween來組合。

Animation: 儲存動畫的值和狀態 AnimationController: 控制動畫,包含:啟動forward()、停止stop()、反向播放reverse()等方法 Tween: 提供begin,end作為動畫變化的取值範圍 Curve:設定動畫使用曲線變化,如非勻速動畫,先加速,後減速等的設定。

動畫示例:

class AnimatePage2 extends StatefulWidget { _AnimatePage createState()=> _AnimatePage();} class _AnimatePage extends State<AnimatePage2> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; initState() { super.initState(); controller = AnimationController(duration: Duration(seconds: 3), vsync: this); //使用彈性曲線,資料變化從0到300 animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn); animation = Tween(begin: 0.0, end: 300.0).animate(animation) ..addListener(() { setState(() { }); }); //啟動動畫(正向執行) controller.forward(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Animate Page"), ), body: Center( child: Image.asset( "assets/images/logo.png", width: animation.value, height: animation.value ), ) ); } dispose() { //路由銷燬時需要釋放動畫資源 controller.dispose(); super.dispose(); }}

很重要的一點,在路由銷燬的時候,需要釋放動畫資源,否則容易導致記憶體洩漏。

顯示Demo:

10.http請求

做業務邏輯,總離不開http請求,接下來,就來看下flutter的http請求是如何做的。

10.1 HttpClient

httpClient在 dart:io庫中,不需要引入第三方庫就可以使用,示例程式碼如下:

使用示例

import 'dart:convert';import 'dart:io';Future _getByHttpClient() async{ //介面地址 const url="https://www.demo.com/api"; //定義httpClient HttpClient client = new HttpClient(); //定義request HttpClientRequest request = await client.getUrl(Uri.parse(url)); //定義reponse HttpClientResponse response = await request.close(); //respinse返回的資料,是字串 String responseBody = await response.transform(utf8.decoder).join(); //關閉httpClient client.close(); //字串需要轉化為JSON var json= jsonDecode(responseBody); return json;}

總的看起來,程式碼還是挺繁瑣的,使用起來並不方便。

10.2 http

這是Dart.dev提供的第三方類庫,地址:https://pub.dev/packages/http

需要先在pubspec.yaml裡新增類庫應用

dependencies: flutter: sdk: flutter json_annotation: ^2.0.0 http: ^0.12.0+2

使用示例:

Future _getByDartHttp() async { // 介面地址 const url="https://www.demo.com/api";//獲取介面的返回值 final response = await http.get(url); //介面的返回值轉化為JSON var json = jsonDecode(response.body); return json;}

這種寫法,比上面的httpClient簡潔了許多。

Dio

國內使用最廣泛的,還是flutterchina在github上提供的Dio第三方庫,目前Star達到了5800多個。

官網地址:https://github.com/flutterchina/dio

使用Dio,因為是第三方庫,所以同樣要先在 pubspec.yaml 新增第三方庫引用。

dependencies: flutter: sdk: flutter json_annotation: ^2.0.0 dio: 2.1.16

使用示例:

import 'package:dio/dio.dart';Future _getByDio() async{ // 介面地址 const url="https://www.demo.com/api"; //定義 Dio例項 Dio dio = new Dio(); //獲取dio返回的Response Response response = await dio.get(url); //返回值轉化為JSON var json=jsonDecode(response.data); return json;}

介面呼叫也是比httpclient簡單很多,可能由於fluterchina在他的官方教程裡,極力推薦這個dio庫,所以目前這個第三方庫的使用情況最為廣泛。和Dart.dev的http不同的是,他需要new一個Dio的例項,在建立例項的時候,還可以傳入更多的擴充套件配置引數。

BaseOptions options = new BaseOptions( baseUrl: "https://www.xx.com/api", connectTimeout: 5000, receiveTimeout: 3000,);Dio dio = new Dio(options);11.吐吐槽

學習Flutter的過程中,其實還是有很多坎坷和需要吐槽的地方。

11.1 牆

因為有牆在,所以在配置flutter,或者下載flutter外掛和第三方庫的時候,需要牆內外來回切換。

11.2 元件過度設計

提供的各種widget元件很多,但是真正核心的元件、常用的元件,也就哪些。 比如Flex 和column、row的關係,比如,Tween 與IntTween,ColorTween,SizeTween等20多個Tween子類之間的關係,你需要花很大的精力,去看每個具體子類的實現差別。

11.3 巢狀太多不適應

因為巢狀層級很多,而且佈局、動畫、功能都在一起,第一次上手Flutter和Dart,這種巢狀關係讓人很暈菜,這個只能去慢慢克服。 另外,多開發自定義的元件,可以讓巢狀關係看起來清晰一些。

11.4 佈局修改會導致巢狀關係修改

前端的html+css分離世界裡,不改變巢狀關係,修改CSS就可以調整佈局。 但是在Flutter裡因為佈局也是巢狀關係,這就導致必須去改變巢狀關係。 要讓巢狀更簡單變動影響更小,頁面拆分成子元件變得尤為重要。

11.5 Dart語言升級

沒錯,語言升級也會導致學習的困擾,外面的資料新舊都有,比如有些是 new Text() ,有些直接是Text() ,新手上路會很暈菜。 其實這都是Dart語言升級導致的,記住Dart升級2.X以後,都不使用new了。感興趣的可以自己去看下Dart的升級變更說明。

11.6 不能熱更新

年中的時候,Google官方宣佈flutter暫不官方支援熱更新,但是閒魚團隊已經有了自己的熱更新方案。 關於熱更新,只能靜觀其變了。 效能、開發效率、熱更新,總是要有取捨的。即使是閒魚團隊,熱更新也是付出了一點點效能下降的代價的,這是你選擇flutter的初衷嗎?還是那句話:權衡得失。

12.結語

隨著 9 月谷歌釋出 Flutter1.9 以及flutter for web,Flutter的元件化思路,使得一份程式碼跨三端變成可能,相信Flutter的未來會更加廣闊。

這不是一篇教程,只是在學習Flutter過程中的一點體驗和經歷,也因為時間關係,研究並不深入,如有疏漏,還請不吝賜教。

學習分享,共勉

題外話,畢竟我在三星小米工作多年,深知技術改革和創新的方向,Flutter作為跨平臺開發技術、Flutter以其美觀、快速、高效、開放等優勢迅速俘獲人心,但很多FLutter興趣愛好者進階學習確實資料,今天我把我搜集和整理的這份學習資料分享給有需要的人,若有關Flutter學習進階可以與我在Flutter跨平臺開發終極之選交流群一起討論交流。私信我【學習】我分享給你

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 在所有平臺上使用React進行構建:頂級框架和工具