前言:很久沒(méi)更新文章了,做個(gè)更新;前段時(shí)間,8 9月份在接觸ml kit、機(jī)器學(xué)習(xí)、tensorflow相關(guān)的(比較耗時(shí)間,而且基本上都是皮毛);由于后面一段時(shí)間工作上實(shí)在是太忙就斷掉了;然后這個(gè)月有時(shí)間開(kāi)始搞搞flutter,后面倒是想試試tensorflow lite,就是不知道有沒(méi)有時(shí)間和動(dòng)力;
這篇主要介紹作為一個(gè)android developer最近這段時(shí)間使用flutter(比較初級(jí))的一些感受吧,具體的技術(shù)細(xì)節(jié)準(zhǔn)備好了,后面的文章會(huì)慢慢分功能模塊整理出來(lái)。
作為一個(gè)android程序員,學(xué)點(diǎn)其他相關(guān)的很正常;比如web前端也懂一點(diǎn),后端也懂一點(diǎn)。但是學(xué)一個(gè)東西肯定不是腦袋一熱就去搞,什么都去搞搞,哪有那么多時(shí)間。畢竟上班拿工資就要寫(xiě)android業(yè)務(wù)的,一周也就下班回來(lái)2、3個(gè)小時(shí)和周末是自由的,還要去掉減壓的時(shí)間。
所以為什么會(huì)去學(xué)flutter呢?
flutter優(yōu)勢(shì):
-
1. 跨平臺(tái)
提起flutter,最先談的就是它的跨平臺(tái)咯。
用dart語(yǔ)言編寫(xiě),一套代碼在android、ios上運(yùn)行。相比于RN頁(yè)面由前端寫(xiě),flutter則是以一種新的形勢(shì)出現(xiàn),獨(dú)立于android、ios、web;這樣的好處是,前端也不會(huì)flutter,大家基本都在同一起跑線(個(gè)人感覺(jué));
當(dāng)demo在兩個(gè)模擬器上都跑起來(lái)的時(shí)候還是很開(kāi)心的,哈哈。
如果后面Fuchsia出來(lái)了,可以跨Fuchsia就更牛逼了。
-
2.性能和開(kāi)發(fā)相關(guān)
flutter號(hào)稱每秒60幀,性能上是媲美甚至是超過(guò)原生開(kāi)發(fā)的;
這點(diǎn)因?yàn)槲覍?xiě)的都是小demo,所以感覺(jué)不到快慢。github上clone別人的幾個(gè)大一點(diǎn)的項(xiàng)目,跑出來(lái)效果基本上感覺(jué)不出是flutter寫(xiě)的,和原生的差不多;關(guān)于熱部署這點(diǎn),其實(shí)算是和android的instant run類似。但是好像要快一些,比如改一下home里面的一些widget狀態(tài),熱部署后秒更新ui,瞬間看到代碼修改后的結(jié)果,還是挺猛的。大大提高了開(kāi)發(fā)效率。不過(guò)就是有bug了,這個(gè)后面缺點(diǎn)再說(shuō)。
上手后開(kāi)發(fā)app還是挺快的。因?yàn)椴还苡檬裁撮_(kāi)發(fā),最后出來(lái)的app肯定是要和產(chǎn)品想要的一樣。所以,熟悉了基本flutter開(kāi)發(fā)流程后,android developer使用flutter開(kāi)發(fā)app流程還是和原生大同小異的。ios不太清楚,但是聽(tīng)一個(gè)ios開(kāi)發(fā)說(shuō),flutter語(yǔ)法以及開(kāi)發(fā)特點(diǎn)上更像oc。不過(guò)android開(kāi)發(fā)者比ios開(kāi)發(fā)者的最明顯的優(yōu)勢(shì)就是flutter支持androidStuido,卻不支持xCode。
flutter 內(nèi)置了很多東西。比如一些小控件圖片資源,網(wǎng)絡(luò)圖片緩存啥的,用起來(lái)很方便。
dart語(yǔ)言特性。寫(xiě)list等數(shù)據(jù)結(jié)構(gòu)、還有類似builder構(gòu)造函數(shù)用起來(lái)挺爽的。
-
3.flutter和google的關(guān)系
這段時(shí)間大家都應(yīng)該聽(tīng)說(shuō)google和甲骨文公司的糾紛,以及前段時(shí)間歐盟android收費(fèi)等消息。
android從java到提供kotlin開(kāi)發(fā),然后到現(xiàn)在flutter的出現(xiàn)。
然后就是新的google Fuchsia系統(tǒng)(統(tǒng)一android和chrome os),也是用dart語(yǔ)言開(kāi)發(fā),不確定是不是flutter。如果后面這個(gè)新的系統(tǒng)真的出來(lái),并且可以在手機(jī)上跑,那么到時(shí)候移動(dòng)端很可能是android ios Fuchsia三分天下了。
這里就有問(wèn)題了(以下只是個(gè)人見(jiàn)解,以及一些危機(jī)意識(shí)):
現(xiàn)在每個(gè)公司除了跨平臺(tái),都有android、ios獨(dú)立的開(kāi)發(fā)小組,那么Fuchsia出來(lái)后呢?三個(gè)小組?然后發(fā)現(xiàn)flutter寫(xiě)的在三個(gè)系統(tǒng)都可以跑,那還有必要開(kāi)三份工資嗎?
或者說(shuō)會(huì)保留一些原生開(kāi)發(fā),可能一些功能跨平臺(tái)做不了,還是要每個(gè)原生系統(tǒng)自己去實(shí)現(xiàn)(模塊的方式)。但是大部分還是跨平臺(tái)去實(shí)現(xiàn)了。如果真是這樣,那么如果只會(huì)android或者只會(huì)ios,到時(shí)候說(shuō)不定真的會(huì)涼涼,難受啊馬飛。
但是這也算是一個(gè)機(jī)會(huì)吧,如果Fuchsia真的火起來(lái)了,一些大廠或者針對(duì)海外市場(chǎng)的公司應(yīng)該會(huì)去占領(lǐng)這個(gè)新的操作系統(tǒng)的市場(chǎng)。到時(shí)候只有小部分開(kāi)發(fā)者會(huì)flutter,而你剛好在其中(熟練&精通),豈不是美滋滋。
-
4.其他實(shí)際一點(diǎn)的
- 今年GDD,閑魚(yú)真是出彩,除了tensorflow lite的應(yīng)用,flutter的應(yīng)用也是超級(jí)厲害,感覺(jué)真是業(yè)界的領(lǐng)頭羊。閑魚(yú)的部分務(wù)模塊已經(jīng)用fluuter接到原來(lái)的框架了,并且經(jīng)受住了千萬(wàn)、億級(jí)別的考驗(yàn);說(shuō)明這東西還是靠譜的。之前還看到知乎上的閑魚(yú)技術(shù)官方號(hào)在招flutter開(kāi)發(fā),牛逼的可以去試一下。
- 現(xiàn)在一些公司的android招聘要求,已經(jīng)把flutter作為和rn、weex一樣的加分項(xiàng)了。
- 如果之前你沒(méi)有系統(tǒng)的通過(guò)官方文檔學(xué)習(xí)(比如學(xué)android、java是通過(guò)別人整理的資料:書(shū)籍、博客、視頻等),可以用flutter中文網(wǎng)來(lái)練練手。英語(yǔ)過(guò)關(guān)的可以直接看英文版的。官方文檔才是第一手資料,看別人整理過(guò)的東西,別人已經(jīng)幫你踩過(guò)坑、思考過(guò)了,而且可能還表達(dá)的不全面。
大部分人都想成為墾荒者吧,互聯(lián)網(wǎng)技術(shù)這塊還是國(guó)外的先進(jìn)一些。如果是一項(xiàng)新技術(shù),應(yīng)該是英文文檔先出來(lái),等整理成中文網(wǎng)站就慢一步了。如果再等國(guó)內(nèi)大佬發(fā)博客、出書(shū)籍就更慢了。
flutter的缺點(diǎn):
說(shuō)說(shuō)個(gè)人最近使用flutter后對(duì)flutter的一些吐槽吧
-
1. flutter的包體積比原生開(kāi)發(fā)的大
會(huì)比android原生apk大一些。因?yàn)殇秩疽娣诺搅薬pp里面。


下面是apk(別人github上的項(xiàng)目,業(yè)務(wù)較少)體積:

(到目前由于經(jīng)驗(yàn)較少,不確定業(yè)務(wù)量增大后,apk大小增長(zhǎng)的速度是不是和原生的一致了。如果本來(lái)apk就有50多M,flutter引擎如果只是增加7M,一共60M,貌似也可以接受)
至于為什么要把引擎放到app里面,現(xiàn)在我也不懂。google了一下,看有人說(shuō)應(yīng)用程序中包含 C / C ++ 引擎和 Dart VM是為了應(yīng)用程序直接使用本機(jī)指令集運(yùn)行,不涉及任何解釋器。
-
2.flutter的ui 刷新問(wèn)題
每次重新繪制那一下,特別是列表滑動(dòng),android上稍微認(rèn)真觀察,就會(huì)發(fā)現(xiàn)會(huì)卡一下。ios不明顯,android比較明顯。閑魚(yú)的詳情頁(yè)也有這種情況。
flutter ui的概念是every thing is widget,就連頁(yè)面也是一個(gè)widget。widget又分有狀態(tài)和無(wú)狀態(tài)。
個(gè)人覺(jué)得吧,無(wú)狀態(tài)的widget就是為了讓Ui不要重新繪制。
猜測(cè)原因(沒(méi)看過(guò)flutter的cpu proflier,純屬瞎BB):list滑動(dòng)刷新通過(guò)有狀態(tài)widegt來(lái)刷新?tīng)顟B(tài)(setState)來(lái)重新繪制頁(yè)面造成的瞬間卡頓。
-
3.flutter是用代碼布局,沒(méi)有xml的概念,對(duì)android程序員不太友好
(demo是stackoverflow上的一個(gè)flutter使用相對(duì)布局的回答,然后答得太好直接被官網(wǎng)引用了,牛逼?。?br>
可能ios開(kāi)發(fā)要好適應(yīng)一些,但是android開(kāi)發(fā)習(xí)慣了xml布局,剛開(kāi)始接觸可能不太適應(yīng)(使用一陣子就習(xí)慣了)。
android里面看Ui布局,一般是通過(guò)xml來(lái)看大概的布局,雖然有時(shí)也會(huì)用代碼動(dòng)態(tài)管理ui,不過(guò)大部分還是習(xí)慣用xml布局。
比如下圖:
flutter的布局是一層套一層,如果要使用復(fù)雜一點(diǎn)的布局,就得嵌套多層。下面的布局是list的一個(gè)小item。
class Song extends StatelessWidget {
const Song({this.title, this.author, this.likes});
final String title;
final String author;
final int likes;
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return new Container(
margin: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 5.0),
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 0),
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.3),
borderRadius: new BorderRadius.circular(5.0),
),
child: new IntrinsicHeight(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(
left: 0, top: 4.0, bottom: 4.0, right: 10.0),
child: new CircleAvatar(
backgroundImage: new NetworkImage(
'http://thecatapi.com/api/images/get?format=src'
'&size=small&type=jpg#${title.hashCode}'),
radius: 20.0,
),
),
new Expanded(
child: new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text(title, style: textTheme.subhead),
new Text(author, style: textTheme.caption),
],
),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 5.0),
child: new InkWell(
child: new Icon(Icons.play_arrow, size: 40.0),
onTap: () {
// TODO(implement)
},
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 5.0),
child: new InkWell(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Icon(Icons.favorite, size: 25.0),
new Text('${likes ?? ''}'),
],
),
onTap: () {
// TODO(implement)
},
),
),
],
),
),
);
}
}

剛開(kāi)始是會(huì)覺(jué)得這個(gè)好麻煩,代碼里面利用row包c(diǎn)hildren,children里面有clumn包c(diǎn)hildren,就像一顆ui結(jié)構(gòu)樹(shù)一樣,然后每個(gè)樹(shù)節(jié)點(diǎn)用類似builder模式傳一些參數(shù)進(jìn)去描述具體節(jié)點(diǎn)特征。(下圖是官網(wǎng)上另一個(gè)demo的例子,直接copy過(guò)來(lái)示意一下,和這個(gè)demo不對(duì)應(yīng))

好消息是可能是因?yàn)閐art和flutter的機(jī)制,雖然沒(méi)有xml看ui結(jié)構(gòu),但是可以通過(guò)代碼旁的結(jié)構(gòu)樹(shù)來(lái)查看。點(diǎn)擊樹(shù)里面的節(jié)點(diǎn)還能對(duì)應(yīng)到具體的代碼位置。還是挺不錯(cuò)的。

-
4.flutter有bug
-
熱部署有時(shí)候有問(wèn)題
雖然flutter的熱部署很厲害,很好用,但是也有熄火的時(shí)候。
一種情況:
如果你的app是多個(gè)頁(yè)面,如果當(dāng)前頁(yè)面在c,但是你改了其他頁(yè)面的代碼想看效果,這時(shí)候熱部署完了之后還是在c頁(yè)面的;你想看到其他頁(yè)面修改后的效果,需要手動(dòng)切到那個(gè)頁(yè)面。這個(gè)可能跟flutter的一個(gè)頁(yè)面也是屬于widget有關(guān)。當(dāng)然如果重新運(yùn)行,他還是會(huì)從main函數(shù)入口開(kāi)始重新執(zhí)行初始化邏輯。
另外一種情況:
上面那種情況其實(shí)還可以接受。但是有時(shí)候熱部署會(huì)突然卡住,然后一直卡在同步數(shù)據(jù)中,一般卡好一會(huì)兒。這時(shí)候因?yàn)樵诘却龍?zhí)行hot reload,所以也點(diǎn)擊不了重新運(yùn)行。
image.png
等一會(huì)就變成這個(gè)樣子,然后就GG了,必須得重新關(guān)掉ide再打開(kāi)。。。
-
flutter sdk會(huì)突然抽風(fēng)
flutter有類似android gradle的管理叫pubspec.yaml
image.png
有時(shí)不小心點(diǎn)到flutter升級(jí)后,升級(jí)完就GG了。不知道是不是操作不當(dāng),然后之前能跑的項(xiàng)目就跑不了了。更正flutter doctor嘗試也不行,最后只好把flutter sdk,flutter plugin,dart plugin全部清掉,又重新裝一遍。
最奇怪的一次是昨天晚上還跑的好好地,今天白天去公司用androidStuido寫(xiě)android項(xiàng)目,完全沒(méi)動(dòng)flutter相關(guān)的東西,晚上回來(lái)就跑不了flutter項(xiàng)目了。各種查,找不到原因,又重新裝了一次。
我每次都是用的github上flutter的dev分支,前前后后大概重裝了3次,現(xiàn)在終于是穩(wěn)定了。 -
5.學(xué)習(xí)成本不小
- flutter算是一種新的開(kāi)發(fā)方式,語(yǔ)言用dart開(kāi)發(fā),雖說(shuō)dart很像很像java,但是有些細(xì)節(jié)和java不太一樣,所以遇到的時(shí)候還是要去查一下。
- 然后就是flutter除了上面說(shuō)的移除了xml的布局,純粹用代碼寫(xiě)布局外。flutter的控件這些還是要花時(shí)間去掌握。和android原生的用法不一樣,相對(duì)布局的概念也有些差異。
- flutter使用的異步線程也和java虛擬機(jī)不太一樣。因?yàn)閖ava里面棧才是線程私有的,堆和方法區(qū)是線程共享的,這就要考慮堆里面數(shù)據(jù)的多線程問(wèn)題。但是flutter里面堆也是線程私有的,所以不用擔(dān)心多線程。但是個(gè)人感覺(jué)如果不花時(shí)間去理解這種模式,后面肯定是會(huì)有問(wèn)題的,雖然目前還沒(méi)遇到(demo)。
- 之前也提到過(guò),除非一個(gè)新項(xiàng)目全部用flutter寫(xiě)(也有可能一些功能要原生去實(shí)現(xiàn))。老的項(xiàng)目里面用flutter,要用模塊的形式接進(jìn)去。就要涉及到flutter和android原生、ios原生相接。這就代表如果android去開(kāi)發(fā)flutter,除了學(xué)習(xí)flutter,后面還是有概率要去看看ios的一些原生開(kāi)發(fā)方式(理想情況是android+flutter和ios+flutter)。類似的接so庫(kù)這些也不太一樣
- 適配問(wèn)題。而且雖說(shuō)一套代碼在android、ios上面跑,但是android、ios的風(fēng)格是不一樣的。有開(kāi)發(fā)經(jīng)驗(yàn)的都知道ui給的圖,最明顯的就是titleBar兩端是不一樣的。
一個(gè)是Material一個(gè)是Cupertino風(fēng)格?,F(xiàn)在我都是按照android的material風(fēng)格寫(xiě)的,如果是做線上項(xiàng)目,肯定也要花時(shí)間去適配ios風(fēng)格的。
不過(guò)android開(kāi)發(fā)嘛,大家都懂得,各種華為、小米、oppo等適配,不就是多一個(gè)apple嘛,哈哈哈。
ps:現(xiàn)在個(gè)人配置:mac pro(雙系統(tǒng)mac windows)、手機(jī)一加5(android)、ipad2018(ios)、遠(yuǎn)程vps(linux)
總結(jié)&后續(xù)
總的來(lái)說(shuō)flutter還是值得去看一看的,畢竟是google推出來(lái)的,國(guó)內(nèi)閑魚(yú)已經(jīng)上線了。
至于學(xué)習(xí)到什么程度需要自己結(jié)合實(shí)際情況把控了,如果能運(yùn)用到公司的項(xiàng)目里面那是最好不過(guò)了,在不荒廢原生開(kāi)發(fā)的情況下all in flutter。如果公司不使用flutter,就看個(gè)人的規(guī)劃和空余時(shí)間有多少吧。
畢竟工作日公司要加班,回去要陪女朋友。
回去要陪女朋友 。 emmmm......看來(lái)我還是有時(shí)間的。
flutter要深入,還是要花很多時(shí)間的。反正慢慢搞嘛,又沒(méi)有明顯的dealine,白天學(xué)android,晚上學(xué)點(diǎn)其他的。
大前端的趨勢(shì)是越來(lái)越明顯了,但是誰(shuí)也說(shuō)不準(zhǔn),說(shuō)不定哪天就突然去世,還是得靠原生開(kāi)發(fā)。

