網站首頁 編程語言 正文
起源
flutter作為一個跨平臺的框架,在繪制上體現出了它跨平臺的良好性能.那么,它是如何從runApp()后 繪制上屏的呢?本文將與你一起去探索這一過程.
ps: 為了思維不中斷, 本文僅對整體流程作分析,不會深入分析具體實現
我們運行一個flutter app ,入口一定是從runApp() 中進行的. 那么flutter 在runApp() 中做了哪些處理呢? 首先,我們從runApp() 這個函數聊起.它是一個需要傳入Widget 的函數.而傳入的Widget ,即首屏渲染所需的Widget.
在此我們應該知道這個概念, 即widget 是flutter 中用來描述ui如何繪制的配置文件,去形容一個組件在整體中的位置、大小.
那么不難推斷出.在runApp() 的過程中,如果Widget是繪制的配置文件. 那么手勢注冊、楨調度等都應該是在此時注冊的. 帶著這樣的推斷我們去源碼中找答案.
分析準備
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
// 這里解釋下:
// ..是flutter中的級聯運算符
// 可以同一個對象上連續調用多個對象的變量或方法
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
在runApp() 中可以看到, 這里實際上也就是調用了三個方法,以下我們對每個方法進行刨析.
ensureInitialized
從字面意思看,這是為了確保已經初始化而調用的方法.它的作用是為了返回WidgetsBinding的對象.如果了解單列模式的話,會發現這么寫實際上就是一個單列模式.
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding._instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
這里我們去挖掘一下WidgetsFlutterBinding內部的構造函數在初始化時做了什么? 它是繼承BingingBase的, 我們進入BingingBase中淺看一下大概的實現, Timeline 和assert這部分代碼我們可以忽略.
ps: assert 在release代碼中不會執行
也就是實際上的結構是這樣的
BindingBase() {
initInstances();
initServiceExtensions();
}
- initInstances() 方法是為了綁定初始化實例和其他的一些狀態.
- initServiceExtensions() 方法是為了綁定初始化服務
這里我們回過頭來看WidgetsFlutterBinding它的一些實現接口, 順序依次是:
接口 | 解釋 |
---|---|
GestureBinding | 實現點擊命中測試 |
SchedulerBinding | 引入了幀的概念 |
ServicesBinding | 提供對插件的訪問 |
PaintingBinding | 解碼圖像 |
SemanticsBinding | 語義樹 |
RendererBinding | 處理render tree |
WidgetsBinding | 處理widget tree |
內部的具體實現這里不再贅述,后續會逐章對這些進行分解、解釋.這里只是去分析整體的流程. 也就是說, 在這里我們完成了對app系統的初始化、推動界面的繪制,獲取手勢等等.
scheduleAttachRootWidget
在一系列服務注冊完之后,我們需要把當前的root widget 掛載到樹上,
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
在attachRootWidget 的方法中, 我們構建了RenderObjectToWidgetAdapter 的對象. 通過RenderObjectToWidgetAdapter 當作Element 和RenderObject 之間的橋梁,
{
final bool isBootstrapFrame = renderViewElement == null;
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
if (isBootstrapFrame) {
SchedulerBinding.instance.ensureVisualUpdate();
}
}
同時,這里 根據renderViewElement 有沒有賦值來判斷是否是第一次加載.如果是第一次加載頁面,會通知界面去刷新ui
scheduleWarmUpFrame
這個方法從字面意思來看 應該是在界面啟動時去執行的一些方法. 首先,我們看一下它的一些引用路徑.發現一共有三個地方的代碼都引用了這個方法
可以看到調用的三個地方分別是:
- allowFirstFrame()
- performReassemble()
- runApp()
好家伙,這不都是類似于繪制的入口函數? 因此,我們可以推斷這里就是一些繪制時初始化時候必須執行的一些代碼.
{
// 這里通過偽代碼簡要了解一下大致實現
//
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle) return;
_warmUpFrame = true;
// 這里把源代碼提前了,由于handle*()的代碼都是通過Timer.run執行的,實際上是
// 一種異步執行,會在下一幀去調用
lockEvents(() async {
await endOfFrame;
timelineTask.finish();
});
// 開始幀回調
handleBeginFrame(null);
// 新幀回調處理
handleDrawFrame();
// 這里和熱重載相關
resetEpoch();
_warmUpFrame = false;
//
if (hadScheduledFrame) scheduleFrame();
}
總結
總結一下, runApp() 通過
- 注冊各種服務
- 注冊ui
- 繪制上屏
最終在屏幕上呈現出ui,其中還有如PipelineOwner、BuildOwner等等非常重要的api,這里暫且不表. 后續我們單章詳細介紹,希望這一次與你一起閱讀的思路可以幫你一起思考啟動的流程.
原文鏈接:https://juejin.cn/post/7168407914221142046
相關推薦
- 2023-01-18 Qt實現制作簡單的計算器_C 語言
- 2022-09-15 Python?并行化執行詳細解析_python
- 2022-11-23 詳解Android創建Handler的必備知識點_Android
- 2022-05-21 kubernetes?k8s入門定義一個Pod_云其它
- 2024-03-10 @Controller、@Service和@Repository注解詳解
- 2022-11-09 關于Rust編譯時報link.exe?not?found錯誤問題_相關技巧
- 2022-08-15 Dubbo3基礎配置安裝及整合Springboot
- 2022-11-11 Python深度學習之Keras模型轉換成ONNX模型流程詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支