flutter setState機(jī)制

個(gè)人網(wǎng)站:chengang.plus

1、定義

setState方法只能定義在State類(lèi)中,執(zhí)行這個(gè)方法之后,能夠更新State限定的StatefulWidget及其子Widget樹(shù)。

在StatefulWidget執(zhí)行createElement方法創(chuàng)建StatefulElement對(duì)象的時(shí)候,會(huì)回調(diào)到StatefulWidget的createState方法,也就回到了我們自定義Widget繼承StatefulWidget的createState方法,從而創(chuàng)建了一個(gè)State對(duì)象。

這個(gè)State持有一個(gè)_element和一個(gè)_widget對(duì)象。

2、State中執(zhí)行

在State類(lèi)中定義了setState方法:

@protected
void setState(VoidCallback fn) {
    final dynamic result = fn() as dynamic;
    _element.markNeedsBuild();
}

2.1 標(biāo)記為dirty

先執(zhí)行我們的閉包函數(shù)fn(),然后執(zhí)行markNeedsBuild,定義在Element類(lèi)中:

void markNeedsBuild() {
    if (!_active)
        return;
    if (dirty)
        return;
    _dirty = true;
    owner.scheduleBuildFor(this);
}

2.2 BuildOwner調(diào)度重建

當(dāng)前Element節(jié)點(diǎn)被標(biāo)記為dirty,同時(shí)調(diào)用owner的scheduleBuildFor方法,owner是BuildOwner類(lèi)型,看看scheduleBuildFor方法:

void scheduleBuildFor(Element element) {
    if (element._inDirtyList) {
        _dirtyElementsNeedsResorting = true;
        return;
    }
    if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
        _scheduledFlushDirtyElements = true;
        onBuildScheduled();
    }
    _dirtyElements.add(element);
    element._inDirtyList = true;
}

BuildOwner用來(lái)管理那些需要更新的Widget。這個(gè)owner最開(kāi)始被初始化的地方在WidgetsBinding的initInstances方法中,隨后初始化了onBuildScheduled方法,對(duì)應(yīng)執(zhí)行的是_handleBuildScheduled,定義在WidgetsBinding類(lèi)中,看看這個(gè)方法:

void _handleBuildScheduled() {
    ensureVisualUpdate();
}

ensureVisualUpdate方法定義在SchedulerBinding類(lèi)中:

void ensureVisualUpdate() {
    switch (schedulerPhase) {
      case SchedulerPhase.idle:
      case SchedulerPhase.postFrameCallbacks:
        scheduleFrame();
        return;
      case SchedulerPhase.transientCallbacks:
      case SchedulerPhase.midFrameMicrotasks:
      case SchedulerPhase.persistentCallbacks:
        return;
    }
}

2.2 調(diào)度繪制

在提交下一幀繪制的時(shí)候會(huì)調(diào)用到scheduleFrame方法,提交給引擎繪制,看看scheduleFrame方法,也定義在SchedulerBinding類(lèi)中:

void scheduleFrame() {
    if (_hasScheduledFrame || !framesEnabled)
      return;
    ensureFrameCallbacksRegistered();
    window.scheduleFrame();//native 'Window_scheduleFrame'
    _hasScheduledFrame = true;
}

@protected
void ensureFrameCallbacksRegistered() {
    window.onBeginFrame ??= _handleBeginFrame;
    window.onDrawFrame ??= _handleDrawFrame;
}

提交給引擎繪制之后,會(huì)收到onDrawFrame的回調(diào),最終執(zhí)行到_handleDrawFrame方法中,對(duì)應(yīng)的是handleDrawFrame方法,定義在SchedulerBinding類(lèi)中:

void handleDrawFrame() {
    Timeline.finishSync(); // end the "Animate" phase
    try {
      // PERSISTENT FRAME CALLBACKS
      _schedulerPhase = SchedulerPhase.persistentCallbacks;
      for (final FrameCallback callback in _persistentCallbacks)
        _invokeFrameCallback(callback, _currentFrameTimeStamp);
    
      // POST-FRAME CALLBACKS
      _schedulerPhase = SchedulerPhase.postFrameCallbacks;
      final List<FrameCallback> localPostFrameCallbacks =
          List<FrameCallback>.from(_postFrameCallbacks);
      _postFrameCallbacks.clear();
      for (final FrameCallback callback in localPostFrameCallbacks)
        _invokeFrameCallback(callback, _currentFrameTimeStamp);
    } finally {
      _schedulerPhase = SchedulerPhase.idle;
      Timeline.finishSync(); // end the Frame
      _currentFrameTimeStamp = null;
    }
}

這個(gè)_persistentCallbacks在之前的章節(jié)有講到過(guò),在RendererBinding的initInstances方法中添加了一個(gè)回調(diào)到這個(gè)List中,對(duì)應(yīng)的是RendererBinding的drawFrame方法,對(duì)對(duì)應(yīng)的節(jié)點(diǎn)進(jìn)行繪制渲染操作。

3、繪制

3.1 開(kāi)始繪制渲染

但是在WidgetsBinding類(lèi)中,也覆寫(xiě)了drawFrame方法。在之前的繪制過(guò)程章節(jié),可以看到WidgetsBinding相當(dāng)于是繼承了RendererBinding接口,所以先調(diào)用WidgetsBinding中的drawFrame方法:

@override
void drawFrame() {
    TimingsCallback firstFrameCallback;
    if (_needToReportFirstFrame) {
      firstFrameCallback = (List<FrameTiming> timings) {
        if (!kReleaseMode) {
          developer.Timeline.instantSync('Rasterized first useful frame');
          developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
        }
        SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback);
        firstFrameCallback = null;
        _firstFrameCompleter.complete();
      };
      // Callback is only invoked when [Window.render] is called. When
      // [sendFramesToEngine] is set to false during the frame, it will not
      // be called and we need to remove the callback (see below).
      SchedulerBinding.instance.addTimingsCallback(firstFrameCallback);
    }
    
    try {
      if (renderViewElement != null)
        buildOwner.buildScope(renderViewElement);
      super.drawFrame();
      buildOwner.finalizeTree();
    } finally {
    }
    if (!kReleaseMode) {
      if (_needToReportFirstFrame && sendFramesToEngine) {
        developer.Timeline.instantSync('Widgets built first useful frame');
      }
    }
    _needToReportFirstFrame = false;
    if (firstFrameCallback != null && !sendFramesToEngine) {
      SchedulerBinding.instance.removeTimingsCallback(firstFrameCallback);
    }
}

看看這里的buildScope方法,定義在BuildOwner方法中:

void buildScope(Element context, [ VoidCallback callback ]) {
    if (callback == null && _dirtyElements.isEmpty)
        return;
    Timeline.startSync('Build', arguments: timelineWhitelistArguments);
    _dirtyElements.sort(Element._sort);
    _dirtyElementsNeedsResorting = false;
    int dirtyCount = _dirtyElements.length;
    int index = 0;
    while (index < dirtyCount) {
        try {
            _dirtyElements[index].rebuild();
        } catch (e, stack) {
        }finally {
            for (final Element element in _dirtyElements) {
                element._inDirtyList = false;
            }
            _dirtyElements.clear();
            _scheduledFlushDirtyElements = false;
            _dirtyElementsNeedsResorting = null;
            Timeline.finishSync();
        }
    }
}

_dirtyElements列表,先從深到淺排序,之后遍歷,遍歷的過(guò)程中執(zhí)行rebuild方法,此時(shí)將所有標(biāo)記為dirty的Element節(jié)點(diǎn)依次執(zhí)行rebuild,preformRebuild,build,updateChild,update方法,執(zhí)行界面更新。

當(dāng)然了,這些build,update操作完成之后,后續(xù)會(huì)將需要繪制的RenderObject添加到需要layout的列表中,等待繪制渲染。

所有繪制完成之后將_dirtyElements列表清空,_inDirtyList標(biāo)記位置為false。

3.2 提交給引擎繪制渲染

看看super.drawFrame(),這里就執(zhí)行到了RendererBinding類(lèi)中,定義如下:

void drawFrame() {
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
    if (sendFramesToEngine) {
      renderView.compositeFrame(); // this sends the bits to the GPU
      pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
      _firstFrameSent = true;
    }
}

這里就是將最終需要繪制渲染的畫(huà)面提交給引擎繪制的地方了,繪制完成之后就在界面顯示更新后的視圖了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容