欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter?runApp到渲染上屏分析詳解

 更新時間:2022年11月22日 15:32:30   作者:WeninerIo  
這篇文章主要為大家介紹了Flutter?runApp到渲染上屏分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

起源

flutter作為一個跨平臺的框架,在繪制上體現出了它跨平臺的良好性能.那么,它是如何從runApp()后 繪制上屏的呢?本文將與你一起去探索這一過程.

ps: 為了思維不中斷, 本文僅對整體流程作分析,不會深入分析具體實現

我們運行一個flutter app ,入口一定是從runApp() 中進行的. 那么flutter 在runApp() 中做了哪些處理呢? 首先,我們從runApp() 這個函數聊起.它是一個需要傳入Widget 的函數.而傳入的Widget ,即首屏渲染所需的Widget.

在此我們應該知道這個概念, 即widget 是flutter 中用來描述ui如何繪制的配置文件,去形容一個組件在整體中的位置、大小.

那么不難推斷出.在runApp() 的過程中,如果Widget是繪制的配置文件. 那么手勢注冊、楨調度等都應該是在此時注冊的. 帶著這樣的推斷我們去源碼中找答案.

分析準備

void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
  // 這里解釋下:
  // ..是flutter中的級聯運算符
  // 可以同一個對象上連續(xù)調用多個對象的變量或方法
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}

在runApp() 中可以看到, 這里實際上也就是調用了三個方法,以下我們對每個方法進行刨析.

ensureInitialized

從字面意思看,這是為了確保已經初始化而調用的方法.它的作用是為了返回WidgetsBinding的對象.如果了解單列模式的話,會發(fā)現這么寫實際上就是一個單列模式.

  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding._instance == null)
      WidgetsFlutterBinding();
    return WidgetsBinding.instance;
  }

這里我們去挖掘一下WidgetsFlutterBinding內部的構造函數在初始化時做了什么? 它是繼承BingingBase的, 我們進入BingingBase中淺看一下大概的實現, Timeline 和assert這部分代碼我們可以忽略.

ps: assert 在release代碼中不會執(zhí)行

也就是實際上的結構是這樣的

 BindingBase() {
    initInstances();
    initServiceExtensions();
  }
  • initInstances() 方法是為了綁定初始化實例和其他的一些狀態(tài).
  • initServiceExtensions() 方法是為了綁定初始化服務

這里我們回過頭來看WidgetsFlutterBinding它的一些實現接口, 順序依次是:

接口解釋
GestureBinding實現點擊命中測試
SchedulerBinding引入了幀的概念
ServicesBinding提供對插件的訪問
PaintingBinding解碼圖像
SemanticsBinding語義樹
RendererBinding處理render tree
WidgetsBinding處理widget tree

內部的具體實現這里不再贅述,后續(xù)會逐章對這些進行分解、解釋.這里只是去分析整體的流程. 也就是說, 在這里我們完成了對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

這個方法從字面意思來看 應該是在界面啟動時去執(zhí)行的一些方法. 首先,我們看一下它的一些引用路徑.發(fā)現一共有三個地方的代碼都引用了這個方法

可以看到調用的三個地方分別是:

  • allowFirstFrame()
  • performReassemble()
  • runApp()

好家伙,這不都是類似于繪制的入口函數? 因此,我們可以推斷這里就是一些繪制時初始化時候必須執(zhí)行的一些代碼.

{
    // 這里通過偽代碼簡要了解一下大致實現
    // 
    if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle) return;
    _warmUpFrame = true;
    // 這里把源代碼提前了,由于handle*()的代碼都是通過Timer.run執(zhí)行的,實際上是
    // 一種異步執(zhí)行,會在下一幀去調用
    lockEvents(() async {
      await endOfFrame;
      timelineTask.finish();
    });
    // 開始幀回調
    handleBeginFrame(null);
    // 新幀回調處理
    handleDrawFrame();
    // 這里和熱重載相關
    resetEpoch();
    _warmUpFrame = false;
    // 
    if (hadScheduledFrame) scheduleFrame();
}

總結

總結一下, runApp() 通過

  • 注冊各種服務
  • 注冊ui
  • 繪制上屏

最終在屏幕上呈現出ui,其中還有如PipelineOwner、BuildOwner等等非常重要的api,這里暫且不表. 后續(xù)我們單章詳細介紹,希望這一次與你一起閱讀的思路可以幫你一起思考啟動的流程.

以上就是Flutter runApp到渲染上屏分析詳解的詳細內容,更多關于Flutter runApp渲染上屏的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:

相關文章

最新評論