成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解讀京東零售云mPaaS中Flutter中熱重載原理

云計算 PaaS
熟悉JS的同學,可能會嗤之以鼻,在N年前就已經用上熱重載了,但是對客戶端開發人員來說,簡直是福音。

本文要點:

  • 了解京東零售云mPaaS中Flutter的熱重載原理,有利于日常開發中高效排查問題;
  • 掌握如何調試斷點Flutter工具鏈源碼;

一、前言

1.1 熱重載是什么?

熟悉JS的同學,可能會嗤之以鼻,在N年前就已經用上熱重載了,但是對客戶端開發人員來說,簡直是福音。

那先來看下Flutter官方的定義:

  • Flutter’s hot reload feature helps you quickly and easily experiment, build UIs, add features, and fix bugs. Hot reload works by injecting updated source code files into the running
  • Dart Virtual Machine (VM). After the VM updates classes with the new versions of fields and functions, the Flutter framework automatically rebuilds the widget tree,
  • allowing you to quickly view the effects of your changes.

簡單來說,就是通過將修改后的源代碼文件注入到正在運行的 Dart 虛擬機來實現,注入之后, Flutter 會自動重新構建 widget 樹。

1.2 為什么需要熱重載?

程序猿在刀耕火種的時代,開發調試是這樣子的:

當項目不大,人數不多的情況下,畫面是非常和諧的,效率也是毋庸置疑的高效。但現實是,在大公司,項目往往很大,編譯巨慢無比,同時開發人員眾多,有著非常嚴格的流程制度,導致看起來本沒有問題的開發調試流程,變得異常的痛苦,降低了個體的效率,這里強調下,指的是個體的效率,個人認為越是完善的流程體系,對個體的約束往往越強,但從團隊的角度去看待效率,一定是能 1+ 1 大于 2 的。

而此時的心情是這樣子的:

[[424264]]

而有了熱重載,開發調試是這樣子的:

心情也就成這樣子的:

[[424266]]

1.3 拋出問題

從熱重載定義來看,不少人腦子里蹦出不少跟我一樣的疑惑:

  • 怎么知道哪個文件被修改?
  • 修改的源代碼到底被轉成什么?
  • 修改的源代碼是怎么注入到Dart虛擬機的?
  • Flutter框架又是怎么觸發widget重繪的?

同時在日常使用熱重載的過程中,也會碰到不少這樣那樣的疑惑:

  • 為什么運行flutter attach后還需要手動輸入r來熱重載?
  • 手動敲r,這么無(gou)語(shi)的設計,我們能做成自動化嗎?

當你在網上看過大量熱重載文章后,又衍生了額外的問題:

  • 嘗試去探索源碼時,case太多,怎么能模擬真實環境?能否斷點調試Flutter源碼?
  • 熱重載看著跟動態化很像,那能否運用在動態化技術上?

不急,本文會對上述疑問進行一一解答。

二、dart的熱重載

由于Flutter采用dart作為開發語言,我們先從dart角度來驗證下熱重載。

2.1 編寫驗證demo

考慮到dart執行完會關閉當前進程,我們寫了個定時器來保證進程存活,同時能看到熱重載效果。

2.2 開啟VMService

終端下執行 dart --enable-vm-service main.dart,其中的main.dart為2.1中代碼文件:

可以看到終端會不斷輸出"Hello JDFlutter"的字符。

2.3 執行熱重載

我們將main.dart文件中打印日志修改為”Hello JD”,同時打開終端輸出的Observatory鏈接地址,如下:

找到我們main.dart的Isolate(讀者可以簡單理解為是dart中的線程,只不過Isolate沒有共享內存),圖中紅圈部分,進入后找到Reload Source:

點擊Reload Source后,終端開始輸出”Hello JD”的字符,完成了一次熱重載過程,如下圖:

2.4 自動化熱重載

還是以上面為例子基礎例子,我們加入文件監聽,并且通過發送消息給vm_service來實現熱重載,代碼如下:

直接運行 dart --enable-vm-service main.dart,期間修改”Hello JDFlutter”為”Hello JD”,運行結果如下:

可以看出,我們成功實現了自動化熱重載,上述代碼跟Dart虛擬機通信步驟如下:

  • 獲取Dart VM的websocket服務URI
  • 通過URI連接上Dart VM的service
  • 通過service獲取Dart VM
  • 通過Dart VM獲取isolateId
  • 通過service重載指定isolateId的任務

2.5 Dart虛擬機可做的事情

到這里,大家可以放飛自我,Dart Service提供了大量對外協議,包含斷點、獲取虛擬機狀態,性能等協議,可以參考:Dart虛擬機服務接口。

三、Flutter的熱重載

Flutter的熱重載,本質是在封裝dart熱重載并且對不同的設備啟動安裝加載等流程,接下來準備好在Flutter源碼世界里翱翔吧,以下分析基于v1.22.5分支的源碼。

俗話說,工欲善其事必先利其器,在源碼翱翔久了,容易迷茫,找不到東西南北,看到關鍵方法,又不知道是不是代碼真實的case,需要能驗證我們的想法,最簡單的辦法打斷點,有針對性的去看源碼。

3.1 IDE斷點

Flutter源碼的下載也很簡單,這里就不贅述了,大家可以上網搜下。Flutter工具鏈的源碼位于packages/flutter_tools下。

本文是通過Android Studio(比較熟)來配置和查看源碼,配置如下:

  • 第一步,先新建一個運行配置,選Dart Command Line App;
  • 第二步,找到Flutter源碼中工具鏈的入口文件,flutter_tools.dart;
  • 第三步,輸入想運行的命令;
  • 第四步,找到要調試的Flutter工程;

一頓配置下來,就可以用工具鏈完美的debug指定Flutter工程的源碼,接下來就是選好設備,點擊debug按鈕,如下圖:

3.2 整體流程

以下是Flutter熱重載流程圖:

簡述為:

  • 代碼改動:工具會掃描工程下的文件,通過修改時間來比對哪些文件被修改;
  • 首次編譯:第一次啟動會生成全量app.dill文件;
  • 增量編譯:對修改的文件編譯生成app.dill.incremental.dill增量文件;
  • 更新文件:將增量產物推送到設備中;
  • UI更新:DartVM收到增量文件后進行合并,并通知Flutter引擎更新UI

整個過程并沒有讓App重啟,從而達到高效開發調試效果。

3.3 源碼分析

3.3.1 run命令流程

我們從flutter run命令為入口分析,類位于packages/flutter_tools/lib/executable.dart中的main()方法,run命令最終實現類位于packages/flutter_tools/lib/src/commands/run.dart。

RunCommand在構造函數中默認開啟了hot標識,如果需要關閉,要新增入參--no-hot。

從run命令的流程,可以看出,主要是做了默認參數設置,參數校驗,flutter設備初始,模式判斷等,熱重載是從HotRunner.run中開始執行。

3.3.2 熱重載流程-首次啟動

在HotRunner中,流程也并不復雜:

可以看出,HotRunner做了三件事:

  • 對目標設備,編譯生成dill文件(有人叫kernel文件,本質是一種中間描述,后文會介紹);
  • 對目標設備,安裝運行App;
  • 對目標設備進行attach,從而開啟attach;

第二步會涉及到不同平臺不同做法,對iOS和Android來說,分別對應xcrun和adb,不是本文重點,流程也比較長,以后有機會再展開講,重點說第一步和第三步。

編譯生成dill文件

最終調用到_compile方法,代碼太過于繁瑣,我們直接斷點看,如下:

從斷點信息可以獲知,dart文件會被轉為kernel文件app.dill,以下截取部分app.dill內容,可以看出app.dill是一份完整的代碼文件,包含了main.dart的內容,右邊為main.dart源文件,左邊為app.dill文件內容:

 

生成的app.dill是一份全量的代碼,接下來編譯不同設備(Android、iOS)的安裝包,同時運行指定的包。

此時生成app.dill的進程,我們暫且稱為“編譯進程”,后續熱重載增量的dill,也是驅動該進程生成。

attach設備

在上述的第二步,設備在啟動運行App時,會打開App中DartVM的Observatory服務,本質是一個websocket服務,按照自定義的jsonrpc2.0協議進行通信,在attach時,會通過URI連接上設備服務,如下圖:

連上DartVM服務后,會注冊幾個熱重載事件:reloadSources,reloadMethod,hotRestart,這幾個事件并不是注冊到App中的Dart虛擬機,而是提供給flutter tool其他命令使用,如下圖:

同時通過DartVM服務,來初始設備中flutter產物,設備中產物路徑是臨時生成,用XXX代替,產物路徑為:

  • Android中為:file:///data/user/0/com.example.flutter_app/code_cache/XXX/flutter_app/
  • iOS模擬器中為:/Users/hexianting/資源庫/Developer/CoreSimulator/Devices/BC003085-8F19-4EF3-AB84-BD44282F79B7(模擬器設備ID)/data/Containers/Data/Application/745DE582-59F1-4193-9692-131E611A9359/tmp/XXX/flutter_app/

具體代碼如下:

3.3.3 觸發熱重載

下面分別從源碼角度,看看到底做了什么?

開發者在執行flutter run或者flutter attach后,在終端中輸入r,即可體驗到重載效果,如果在Android Studio和VSCode中,直接Ctrl+S或者Cmd+S即可。

對應到源碼入口:

不管是HotReload還是HotRestart,最終都是調用HotRunner.restart方法,一路跟進,最終會到某個具體設備update方法,并再次調用上述《熱重載流程-首次啟動》中的_compile方法,通知編譯進程生成增量的dill文件app.dill.incremental.dill。那這個增量文件到底是什么呢?demo中修改字符串"Flutter Demo Home Page"為"Flutter Demo Home Page2",來看看dill文件內容:

第一張圖為修改前,第二種為修改后,第三張為增量的dill內容。可以看出增量的dill文件僅包含改動的dart文件代碼。

生成增量的dill后,會通過_DevFSHttpWriter寫入設備,如下圖:

當同步完增量文件,最后還需要通知DartVM去刷新UI界面,這個步驟就跟我們上述的2.4節內容類似:

vmService.reloadSources最終調用了_call方法,這是一個dart官方庫,如下:

HotRestart與HotReload區別

Flutter官方提供兩種快速調試方法,一種是HotReload,另一種是HotRestart。前者無感知局部刷新,體驗最好,但是缺點也很明顯,適用比較局限,可以參考官網給出樣例:HotReload,主要有這幾種場景不適用:

  • enum改成class類;
  • 字體修改;
  • 泛類型修改;
  • Android和iOS原生修改;

而在HotRestart流程中,相比HotReload流程,增加了清除資源操作,同時不再生成增量的dill文件,每次改動都是生成全量的app.dill文件,該細節就不展開,感興趣讀者可以debug源碼看。

上述可以看出HotRestart額外處理了一些事情,包括殺掉非UI的isolate,重置UI的isolate等。

對于dill文件同步到設備中位置,不同設備不一樣:

  • Android:file:///data/user/0/com.example.flutter_app/code_cache/XXX/flutter_app/lib/
  • iOS模擬器:/Users/hexianting/Library/Developer/CoreSimulator/Devices/BC003085-8F19-4EF3-AB84-BD44282F79B7(模擬器設備ID)/data/Containers/Data/Application/9C8E4694-AC99-4A5C-BC46-63567F1C6FD9/tmp/XXX/flutter_app/lib/

至此,熱重載源碼就告一段落,很多奇技淫巧并不能一一展現,值得大家動手去看看。

四、總結

經過上述一頓探索,文章最早提出的幾個疑問,想必都有了答案。這里只是介紹了Flutter源碼的冰山一角,更多源碼還需要繼續探索,通過閱讀源碼,可做的事情很多:

  • 通過文件監聽+vm_service通信,干掉手動輸入r或者R的這種無(gou)語(shi)設計;
  • 源碼中并沒有限制多個設備,flutter run同時運行在多個模擬器中,并開啟熱重載;
  • iOS模擬器不重新安裝App的情況下,直接替換模擬器中的flutter產物,以達到快速調試手段;
  • debug狀態下的DartVM可以通過熱重載來動態化,但性能較低,與谷歌Flutter的高性能目標不符;

總之,可做的事情很多,那我們看源碼的意義就非常清晰:

  • 深入了解Flutter運行機制,去定制Flutter框架;
  • 通過研究這些頂級工程師的實現思路,去完善我們自己的邏輯體系,從而成為一個更加嚴謹的人。

五、參考資料

  • https://flutter.dev/docs/development/tools/hot-reload
  • http://gityuan.com/2019/09/07/flutter_run/
  • https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md
  • http://static.kancloud.cn/alex_wsc/flutter_demo/1570089

 

責任編輯:未麗燕 來源: 京東零售云
相關推薦

2021-09-17 18:40:55

京東mPaaS移動端

2024-07-11 08:09:21

2019-03-21 19:19:35

新零售阿里云零售云

2021-09-16 18:44:05

京東云PaaS平臺Android

2018-01-22 10:33:01

云計算 新零售

2021-11-04 08:00:00

人工智能機器學習技術

2023-03-30 10:06:58

2016-10-19 18:31:13

云存儲

2023-05-11 08:00:30

2018-03-20 09:56:50

新零售

2017-09-30 10:00:41

2021-09-08 18:12:57

京東零售云

2020-06-07 10:07:04

機器人零售業人工智能

2022-06-28 13:41:43

京東數據處理

2022-05-18 13:24:47

京東調優實踐

2018-06-06 17:39:03

2017-10-30 17:18:15

阿里云

2021-08-13 11:38:51

京東零售云智能出行
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美成人一级 | 五月婷婷在线视频 | 国产综合精品一区二区三区 | 国产在线视频99 | 97国产一区二区精品久久呦 | 亚洲欧美日韩在线 | 涩涩操 | 精品欧美一区免费观看α√ | 青青草久久 | 99久久精品免费看国产四区 | 久久久久久久久久久久久久av | 日韩喷潮 | 久久手机视频 | 999观看免费高清www | 国产特黄一级 | 色婷婷综合在线观看 | 午夜寂寞福利视频 | 日韩在线不卡视频 | 一区二区免费在线 | 亚洲日日 | 国产香蕉视频在线播放 | 一二三区视频 | 亚洲视频在线观看 | 日本中文字幕在线视频 | 日日爽 | 一级电影免费看 | 欧美精品一区二区三区一线天视频 | 久久久久久久综合色一本 | 久久国品片 | 日韩免费网 | 羞羞的视频网站 | 亚洲毛片网站 | 99在线播放| 久久一热 | 日韩一区二区av | 免费一区在线观看 | 日韩视频免费 | 国产精品久久 | 亚洲天堂影院 | 97免费在线视频 | 精品欧美乱码久久久久久1区2区 |