Flutter开发进阶之瞧瞧BuildOwner

news2024/11/15 4:09:30

Flutter开发进阶之瞧瞧BuildOwner

上回说到关于Element Tree的构建还缺最后一块拼图,build的重要过程中会调用_element!.markNeedsBuild();,而markNeedsBuild会调用owner!.scheduleBuildFor(this);
在Flutter框架中,BuildOwner负责管理构建过程,它持有当前构建周期的所有相关信息,并协调WidgetElement的转换过程。
Flutter开发进阶
让我们看看BuildOwnerElement中的定义。

/*
  The object that manages the lifecycle of this element.
  */
  
  BuildOwner? get owner => _owner;
  BuildOwner? _owner;


  void mount(Element? parent, Object? newSlot) {
    assert(_lifecycleState == _ElementLifecycle.initial);
    assert(_parent == null);
    assert(
        parent == null || parent._lifecycleState == _ElementLifecycle.active);
    assert(slot == null);
    _parent = parent;
    _slot = newSlot;
    _lifecycleState = _ElementLifecycle.active;
    _depth = _parent != null ? _parent!.depth + 1 : 1;
    if (parent != null) {
      _owner = parent.owner;
    }
    assert(owner != null);
    final Key? key = widget.key;
    if (key is GlobalKey) {
      owner!._registerGlobalKey(key, this);
    }
    _updateInheritance();
    attachNotificationTree();
  }

可知_owner在同一个Element Tree下为唯一。
再来看看BuildOwner的源码。

class BuildOwner {
  
  BuildOwner({this.onBuildScheduled, FocusManager? focusManager})
      : focusManager =
            focusManager ?? (FocusManager()..registerGlobalHandlers());

  VoidCallback? onBuildScheduled;

  final _InactiveElements _inactiveElements = _InactiveElements();

  final List<Element> _dirtyElements = <Element>[];
  bool _scheduledFlushDirtyElements = false;

  bool? _dirtyElementsNeedsResorting;

  bool get _debugIsInBuildScope => _dirtyElementsNeedsResorting != null;

  FocusManager focusManager;

  void scheduleBuildFor(Element element) {
    assert(element.owner == this);
    assert(() {
      if (debugPrintScheduleBuildForStacks) {
        debugPrintStack(
            label:
                'scheduleBuildFor() called for $element${_dirtyElements.contains(element) ? " (ALREADY IN LIST)" : ""}');
      }
      if (!element.dirty) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary(
              'scheduleBuildFor() called for a widget that is not marked as dirty.'),
          element.describeElement(
              'The method was called for the following element'),
          ErrorDescription(
            'This element is not current marked as dirty. Make sure to set the dirty flag before '
            'calling scheduleBuildFor().',
          ),
          ErrorHint(
            'If you did not attempt to call scheduleBuildFor() yourself, then this probably '
            'indicates a bug in the widgets framework. Please report it:\n'
            '  https:github.com/flutter/flutter/issues/new?template=2_bug.yml',
          ),
        ]);
      }
      return true;
    }());
    if (element._inDirtyList) {
      assert(() {
        if (debugPrintScheduleBuildForStacks) {
          debugPrintStack(
              label:
                  'BuildOwner.scheduleBuildFor() called; _dirtyElementsNeedsResorting was $_dirtyElementsNeedsResorting (now true); dirty list is: $_dirtyElements');
        }
        if (!_debugIsInBuildScope) {
          throw FlutterError.fromParts(<DiagnosticsNode>[
            ErrorSummary(
                'BuildOwner.scheduleBuildFor() called inappropriately.'),
            ErrorHint(
              'The BuildOwner.scheduleBuildFor() method should only be called while the '
              'buildScope() method is actively rebuilding the widget tree.',
            ),
          ]);
        }
        return true;
      }());
      _dirtyElementsNeedsResorting = true;
      return;
    }
    if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
      _scheduledFlushDirtyElements = true;
      onBuildScheduled!();
    }
    _dirtyElements.add(element);
    element._inDirtyList = true;
    assert(() {
      if (debugPrintScheduleBuildForStacks) {
        debugPrint('...dirty list is now: $_dirtyElements');
      }
      return true;
    }());
  }

  int _debugStateLockLevel = 0;
  bool get _debugStateLocked => _debugStateLockLevel > 0;

  bool get debugBuilding => _debugBuilding;
  bool _debugBuilding = false;
  Element? _debugCurrentBuildTarget;

  void lockState(VoidCallback callback) {
    assert(_debugStateLockLevel >= 0);
    assert(() {
      _debugStateLockLevel += 1;
      return true;
    }());
    try {
      callback();
    } finally {
      assert(() {
        _debugStateLockLevel -= 1;
        return true;
      }());
    }
    assert(_debugStateLockLevel >= 0);
  }

  ('vm:notify-debugger-on-exception')
  void buildScope(Element context, [VoidCallback? callback]) {
    if (callback == null && _dirtyElements.isEmpty) {
      return;
    }
    assert(_debugStateLockLevel >= 0);
    assert(!_debugBuilding);
    assert(() {
      if (debugPrintBuildScope) {
        debugPrint(
            'buildScope called with context $context; dirty list is: $_dirtyElements');
      }
      _debugStateLockLevel += 1;
      _debugBuilding = true;
      return true;
    }());
    if (!kReleaseMode) {
      Map<String, String>? debugTimelineArguments;
      assert(() {
        if (debugEnhanceBuildTimelineArguments) {
          debugTimelineArguments = <String, String>{
            'dirty count': '${_dirtyElements.length}',
            'dirty list': '$_dirtyElements',
            'lock level': '$_debugStateLockLevel',
            'scope context': '$context',
          };
        }
        return true;
      }());
      FlutterTimeline.startSync('BUILD', arguments: debugTimelineArguments);
    }
    try {
      _scheduledFlushDirtyElements = true;
      if (callback != null) {
        assert(_debugStateLocked);
        Element? debugPreviousBuildTarget;
        assert(() {
          debugPreviousBuildTarget = _debugCurrentBuildTarget;
          _debugCurrentBuildTarget = context;
          return true;
        }());
        _dirtyElementsNeedsResorting = false;
        try {
          callback();
        } finally {
          assert(() {
            assert(_debugCurrentBuildTarget == context);
            _debugCurrentBuildTarget = debugPreviousBuildTarget;
            _debugElementWasRebuilt(context);
            return true;
          }());
        }
      }
      _dirtyElements.sort(Element._sort);
      _dirtyElementsNeedsResorting = false;
      int dirtyCount = _dirtyElements.length;
      int index = 0;
      while (index < dirtyCount) {
        final Element element = _dirtyElements[index];
        assert(element._inDirtyList);
        assert(() {
          if (element._lifecycleState == _ElementLifecycle.active &&
              !element._debugIsInScope(context)) {
            throw FlutterError.fromParts(<DiagnosticsNode>[
              ErrorSummary(
                  'Tried to build dirty widget in the wrong build scope.'),
              ErrorDescription(
                'A widget which was marked as dirty and is still active was scheduled to be built, '
                'but the current build scope unexpectedly does not contain that widget.',
              ),
              ErrorHint(
                'Sometimes this is detected when an element is removed from the widget tree, but the '
                'element somehow did not get marked as inactive. In that case, it might be caused by '
                'an ancestor element failing to implement visitChildren correctly, thus preventing '
                'some or all of its descendants from being correctly deactivated.',
              ),
              DiagnosticsProperty<Element>(
                'The root of the build scope was',
                context,
                style: DiagnosticsTreeStyle.errorProperty,
              ),
              DiagnosticsProperty<Element>(
                'The offending element (which does not appear to be a descendant of the root of the build scope) was',
                element,
                style: DiagnosticsTreeStyle.errorProperty,
              ),
            ]);
          }
          return true;
        }());
        final bool isTimelineTracked =
            !kReleaseMode && _isProfileBuildsEnabledFor(element.widget);
        if (isTimelineTracked) {
          Map<String, String>? debugTimelineArguments;
          assert(() {
            if (kDebugMode && debugEnhanceBuildTimelineArguments) {
              debugTimelineArguments =
                  element.widget.toDiagnosticsNode().toTimelineArguments();
            }
            return true;
          }());
          FlutterTimeline.startSync(
            '${element.widget.runtimeType}',
            arguments: debugTimelineArguments,
          );
        }
        try {
          element.rebuild();
        } catch (e, stack) {
          _reportException(
            ErrorDescription('while rebuilding dirty elements'),
            e,
            stack,
            informationCollector: () => <DiagnosticsNode>[
              if (kDebugMode && index < _dirtyElements.length)
                DiagnosticsDebugCreator(DebugCreator(element)),
              if (index < _dirtyElements.length)
                element.describeElement(
                    'The element being rebuilt at the time was index $index of $dirtyCount')
              else
                ErrorHint(
                    'The element being rebuilt at the time was index $index of $dirtyCount, but _dirtyElements only had ${_dirtyElements.length} entries. This suggests some confusion in the framework internals.'),
            ],
          );
        }
        if (isTimelineTracked) {
          FlutterTimeline.finishSync();
        }
        index += 1;
        if (dirtyCount < _dirtyElements.length ||
            _dirtyElementsNeedsResorting!) {
          _dirtyElements.sort(Element._sort);
          _dirtyElementsNeedsResorting = false;
          dirtyCount = _dirtyElements.length;
          while (index > 0 && _dirtyElements[index - 1].dirty) {
          
            index -= 1;
          }
        }
      }
      assert(() {
        if (_dirtyElements.any((Element element) =>
            element._lifecycleState == _ElementLifecycle.active &&
            element.dirty)) {
          throw FlutterError.fromParts(<DiagnosticsNode>[
            ErrorSummary('buildScope missed some dirty elements.'),
            ErrorHint(
                'This probably indicates that the dirty list should have been resorted but was not.'),
            Element.describeElements(
                'The list of dirty elements at the end of the buildScope call was',
                _dirtyElements),
          ]);
        }
        return true;
      }());
    } finally {
      for (final Element element in _dirtyElements) {
        assert(element._inDirtyList);
        element._inDirtyList = false;
      }
      _dirtyElements.clear();
      _scheduledFlushDirtyElements = false;
      _dirtyElementsNeedsResorting = null;
      if (!kReleaseMode) {
        FlutterTimeline.finishSync();
      }
      assert(_debugBuilding);
      assert(() {
        _debugBuilding = false;
        _debugStateLockLevel -= 1;
        if (debugPrintBuildScope) {
          debugPrint('buildScope finished');
        }
        return true;
      }());
    }
    assert(_debugStateLockLevel >= 0);
  }

  Map<Element, Set<GlobalKey>>?
      _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans;

  void _debugTrackElementThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans(
      Element node, GlobalKey key) {
    _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans ??=
        HashMap<Element, Set<GlobalKey>>();
    final Set<GlobalKey> keys =
        _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans!
            .putIfAbsent(node, () => HashSet<GlobalKey>());
    keys.add(key);
  }

  void _debugElementWasRebuilt(Element node) {
    _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans
        ?.remove(node);
  }

  final Map<GlobalKey, Element> _globalKeyRegistry = <GlobalKey, Element>{};

  
  final Set<Element>? _debugIllFatedElements =
      kDebugMode ? HashSet<Element>() : null;
      
  
  final Map<Element, Map<Element, GlobalKey>>? _debugGlobalKeyReservations =
      kDebugMode ? <Element, Map<Element, GlobalKey>>{} : null;

  int get globalKeyCount => _globalKeyRegistry.length;

  void _debugRemoveGlobalKeyReservationFor(Element parent, Element child) {
    assert(() {
      _debugGlobalKeyReservations?[parent]?.remove(child);
      return true;
    }());
  }

  void _registerGlobalKey(GlobalKey key, Element element) {
    assert(() {
      if (_globalKeyRegistry.containsKey(key)) {
        final Element oldElement = _globalKeyRegistry[key]!;
        assert(element.widget.runtimeType != oldElement.widget.runtimeType);
        _debugIllFatedElements?.add(oldElement);
      }
      return true;
    }());
    _globalKeyRegistry[key] = element;
  }

  void _unregisterGlobalKey(GlobalKey key, Element element) {
    assert(() {
      if (_globalKeyRegistry.containsKey(key) &&
          _globalKeyRegistry[key] != element) {
        final Element oldElement = _globalKeyRegistry[key]!;
        assert(element.widget.runtimeType != oldElement.widget.runtimeType);
      }
      return true;
    }());
    if (_globalKeyRegistry[key] == element) {
      _globalKeyRegistry.remove(key);
    }
  }

  void _debugReserveGlobalKeyFor(Element parent, Element child, GlobalKey key) {
    assert(() {
      _debugGlobalKeyReservations?[parent] ??= <Element, GlobalKey>{};
      _debugGlobalKeyReservations?[parent]![child] = key;
      return true;
    }());
  }

  void _debugVerifyGlobalKeyReservation() {
    assert(() {
      final Map<GlobalKey, Element> keyToParent = <GlobalKey, Element>{};
      _debugGlobalKeyReservations
          ?.forEach((Element parent, Map<Element, GlobalKey> childToKey) {
       
        if (parent._lifecycleState == _ElementLifecycle.defunct ||
            parent.renderObject?.attached == false) {
          return;
        }
        childToKey.forEach((Element child, GlobalKey key) {
          if (child._parent == null) {
            return;
          }
          
          if (keyToParent.containsKey(key) && keyToParent[key] != parent) {
            
            final Element older = keyToParent[key]!;
            final Element newer = parent;
            final FlutterError error;
            if (older.toString() != newer.toString()) {
              error = FlutterError.fromParts(<DiagnosticsNode>[
                ErrorSummary('Multiple widgets used the same GlobalKey.'),
                ErrorDescription(
                  'The key $key was used by multiple widgets. The parents of those widgets were:\n'
                  '- $older\n'
                  '- $newer\n'
                  'A GlobalKey can only be specified on one widget at a time in the widget tree.',
                ),
              ]);
            } else {
              error = FlutterError.fromParts(<DiagnosticsNode>[
                ErrorSummary('Multiple widgets used the same GlobalKey.'),
                ErrorDescription(
                  'The key $key was used by multiple widgets. The parents of those widgets were '
                  'different widgets that both had the following description:\n'
                  '  $parent\n'
                  'A GlobalKey can only be specified on one widget at a time in the widget tree.',
                ),
              ]);
            }
            
            if (child._parent != older) {
              older.visitChildren((Element currentChild) {
                if (currentChild == child) {
                  older.forgetChild(child);
                }
              });
            }
            if (child._parent != newer) {
              newer.visitChildren((Element currentChild) {
                if (currentChild == child) {
                  newer.forgetChild(child);
                }
              });
            }
            throw error;
          } else {
            keyToParent[key] = parent;
          }
        });
      });
      _debugGlobalKeyReservations?.clear();
      return true;
    }());
  }

  void _debugVerifyIllFatedPopulation() {
    assert(() {
      Map<GlobalKey, Set<Element>>? duplicates;
      for (final Element element
          in _debugIllFatedElements ?? const <Element>{}) {
        if (element._lifecycleState != _ElementLifecycle.defunct) {
          assert(element.widget.key != null);
          final GlobalKey key = element.widget.key! as GlobalKey;
          assert(_globalKeyRegistry.containsKey(key));
          duplicates ??= <GlobalKey, Set<Element>>{};
          Uses ordered set to produce consistent error message.
          final Set<Element> elements =
              duplicates.putIfAbsent(key, () => <Element>{});
          elements.add(element);
          elements.add(_globalKeyRegistry[key]!);
        }
      }
      _debugIllFatedElements?.clear();
      if (duplicates != null) {
        final List<DiagnosticsNode> information = <DiagnosticsNode>[];
        information
            .add(ErrorSummary('Multiple widgets used the same GlobalKey.'));
        for (final GlobalKey key in duplicates.keys) {
          final Set<Element> elements = duplicates[key]!;
          
          information.add(Element.describeElements(
              'The key $key was used by ${elements.length} widgets', elements));
        }
        information.add(ErrorDescription(
            'A GlobalKey can only be specified on one widget at a time in the widget tree.'));
        throw FlutterError.fromParts(information);
      }
      return true;
    }());
  }

  ('vm:notify-debugger-on-exception')
  void finalizeTree() {
    if (!kReleaseMode) {
      FlutterTimeline.startSync('FINALIZE TREE');
    }
    try {
      lockState(
          _inactiveElements._unmountAll); 
      assert(() {
        try {
          _debugVerifyGlobalKeyReservation();
          _debugVerifyIllFatedPopulation();
          if (_debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans !=
                  null &&
              _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans!
                  .isNotEmpty) {
            final Set<GlobalKey> keys = HashSet<GlobalKey>();
            for (final Element element
                in _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans!
                    .keys) {
              if (element._lifecycleState != _ElementLifecycle.defunct) {
                keys.addAll(
                    _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans![
                        element]!);
              }
            }
            if (keys.isNotEmpty) {
              final Map<String, int> keyStringCount = HashMap<String, int>();
              for (final String key
                  in keys.map<String>((GlobalKey key) => key.toString())) {
                if (keyStringCount.containsKey(key)) {
                  keyStringCount.update(key, (int value) => value + 1);
                } else {
                  keyStringCount[key] = 1;
                }
              }
              final List<String> keyLabels = <String>[];
              keyStringCount.forEach((String key, int count) {
                if (count == 1) {
                  keyLabels.add(key);
                } else {
                  keyLabels.add(
                      '$key ($count different affected keys had this toString representation)');
                }
              });
              final Iterable<Element> elements =
                  _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans!
                      .keys;
              final Map<String, int> elementStringCount =
                  HashMap<String, int>();
              for (final String element in elements
                  .map<String>((Element element) => element.toString())) {
                if (elementStringCount.containsKey(element)) {
                  elementStringCount.update(element, (int value) => value + 1);
                } else {
                  elementStringCount[element] = 1;
                }
              }
              final List<String> elementLabels = <String>[];
              elementStringCount.forEach((String element, int count) {
                if (count == 1) {
                  elementLabels.add(element);
                } else {
                  elementLabels.add(
                      '$element ($count different affected elements had this toString representation)');
                }
              });
              assert(keyLabels.isNotEmpty);
              final String the = keys.length == 1 ? ' the' : '';
              final String s = keys.length == 1 ? '' : 's';
              final String were = keys.length == 1 ? 'was' : 'were';
              final String their = keys.length == 1 ? 'its' : 'their';
              final String respective =
                  elementLabels.length == 1 ? '' : ' respective';
              final String those = keys.length == 1 ? 'that' : 'those';
              final String s2 = elementLabels.length == 1 ? '' : 's';
              final String those2 =
                  elementLabels.length == 1 ? 'that' : 'those';
              final String they = elementLabels.length == 1 ? 'it' : 'they';
              final String think =
                  elementLabels.length == 1 ? 'thinks' : 'think';
              final String are = elementLabels.length == 1 ? 'is' : 'are';
              
              throw FlutterError.fromParts(<DiagnosticsNode>[
                ErrorSummary('Duplicate GlobalKey$s detected in widget tree.'),
               
                ErrorDescription(
                  'The following GlobalKey$s $were specified multiple times in the widget tree. This will lead to '
                  'parts of the widget tree being truncated unexpectedly, because the second time a key is seen, '
                  'the previous instance is moved to the new location. The key$s $were:\n'
                  '- ${keyLabels.join("\n ")}\n'
                  'This was determined by noticing that after$the widget$s with the above global key$s $were moved '
                  'out of $their$respective previous parent$s2, $those2 previous parent$s2 never updated during this frame, meaning '
                  'that $they either did not update at all or updated before the widget$s $were moved, in either case '
                  'implying that $they still $think that $they should have a child with $those global key$s.\n'
                  'The specific parent$s2 that did not update after having one or more children forcibly removed '
                  'due to GlobalKey reparenting $are:\n'
                  '- ${elementLabels.join("\n ")}'
                  '\nA GlobalKey can only be specified on one widget at a time in the widget tree.',
                ),
              ]);
            }
          }
        } finally {
          _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans
              ?.clear();
        }
        return true;
      }());
    } catch (e, stack) {
     
      _reportException(
          ErrorSummary('while finalizing the widget tree'), e, stack);
    } finally {
      if (!kReleaseMode) {
        FlutterTimeline.finishSync();
      }
    }
  }

  void reassemble(Element root) {
    if (!kReleaseMode) {
      FlutterTimeline.startSync('Preparing Hot Reload (widgets)');
    }
    try {
      assert(root._parent == null);
      assert(root.owner == this);
      root.reassemble();
    } finally {
      if (!kReleaseMode) {
        FlutterTimeline.finishSync();
      }
    }
  }
}

我们忽略debug部分的内容,BuildOwner作为一个基类,void scheduleBuildFor(Element element)方法会将一个需要重新构建的Element添加进_dirtyElements中,然后会Flutter通过调用WidgetsBinding.drawFrame方法,内部会调用buildScope完成重新构建。
综合前几篇文章我们了解到,Widget本身只存储了UI的结构数据,在Widget的初始化过程中会将自身作为参数调用Element的初始化方法创建对应的Element,它是持有WidgetStateBuildOwner的实例,它可以包含其他子Element形成Tree,Element通过State的状态管理去进行对应的生命周期管理,同个Tree下Element对应一个根BuildOwner_owner = parent.owner;它负责协调构建过程,当Element添加进_dirtyElements中时,Flutter循环调用的WidgetsBinding.drawFrameWidgetsFlutterBinding.ensureInitialized()runApp()后会激活的循环)会重新构建Tree渲染到屏幕上。
以上完成build闭环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础--128陷阱

问题引入 Integer a 123; Integer b 123; System.out.println(ab); 结果为true。 但是如果代码如下 Integer a 1230;Integer b 1230;System.out.println(ab); 这个的结果就是false。 问题解决 当Integer a 123时&#xff0c;其实他底层自动转换成了Integer a Inte…

数据库专题(oracle基础和进阶)

前言 本专题主要记录自己最近学的数据库&#xff0c;有兴趣一起补习的可以一起看看&#xff0c;有补充和不足之处请多多指出。希望专题可以给自己还有读者带去一点点提高。 数据库基本概念 本模块有参考&#xff1a;数据库基本概念-CSDN博客 数据库管理系统是一个由互相关联的…

Arduino+ESP8266+华为云物联网平台实现智能开关

前言 最近在做一个物联网项目&#xff0c;涉及到智能开关的开发。目前已经实现简单的TCP通信远程控制&#xff0c;但是考虑到后期的设备管理以及设备通信所需要的技术和服务器的维护成本&#xff0c;我决定将设备接入云平台。本文将详细阐述如何利用华为云的物联网平台&#x…

Linux系统下安装部署Linux管理面板1panel

目录 一 1panel介绍 1、1Panel简介 2、1Panel特点 二、本地环境规划 1、本此实验目的 2、本地环境部署 三、部署1Panel&#xff08;在线安装&#xff09; 1.创建安装目录 2.一键部署1Panel 3.检查1Panel服务运行状态 4.检查1Panel监听端口 四、关闭防火墙和selinux…

小动物主动跑轮和被动跑轮的功能和目的?

小动物主动跑轮和被动跑轮在运动方式、实验目的和设计构造方面上是有区别的。 运动方式不同。主动跑轮是由动物自主运动来推动跑轮转动的。这种设置可以真实地反映动物自发的运动情况。相对地&#xff0c;被动跑轮则是一种强迫运动的方式&#xff0c;通常由电机带动跑轮转动从…

视频生成Sora的全面解析:从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等

前言 真没想到&#xff0c;距离视频生成上一轮的集中爆发(详见《Sora之前的视频生成发展史&#xff1a;从Gen2、Emu Video到PixelDance、SVD、Pika 1.0》)才过去三个月&#xff0c;没想OpenAI一出手&#xff0c;该领域又直接变天了 自打2.16日OpenAI发布sora以来(其开发团队包…

基于yolov8安全帽检测的系统

基于yolov8安全帽检测的系统 项目描述&#xff1a; 安全头盔检测&#xff08;计算机视觉&#xff09; 1.自训练数据集1538张数据图片&#xff0c;进行标注&#xff0c;并进行100轮的训练&#xff0c;准确率达0.966 2.使用 Flask 和 Ultralytics YOLOv8 模型开发了一个 Web 应…

Matlab有限差分法求解狄利克雷(Dirichlet)边界的泊松(Poisson)问题,边界值为任意值

参考l链接&#xff1a; 有限差分法简介有限差分法-二维泊松方程及其Matlab程序实现弹性力学方程 有限差分法matlab,泊松方程的有限差分法的MATLAB实现 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Matrix method for Poisson Equation …

景联文科技上新高质量大模型训练数据!

在过去的一年中&#xff0c;人工智能领域呈现出了风起云涌的态势&#xff0c;其中模型架构、训练数据、多模态技术、超长上下文处理以及智能体发展等方面均取得了突飞猛进的发展。 在3月24日举办的2024全球开发者先锋大会的大模型前沿论坛上&#xff0c;上海人工智能实验室的领…

[Linux]知识整理(持续更新)

前言 Linux的目录结构 Linux的目录结构是一个树型结构 Windows 系统可以拥有多个盘符, 如 C盘、D盘、E盘 Linux没有盘符这个概念, 只有一个根目录 /, 所有文件都在它下面 Linux路径的描述方式 第一章 基本命令 命令格式 例:ls –la /etc 说明: 1)个别命令使用不遵循…

照片尺寸怎么修改?高效快速处理方法

在分享照片到不同平台时&#xff0c;也需要符合不同尺寸要求&#xff0c;在不同场景中&#xff0c;应该如何修改图片尺寸呢&#xff1f;还有不同的证件类型有着不同的证件照尺寸要求&#xff0c;因此我们需要根据要求对证件照尺寸进行调整&#xff0c;接下来就介绍几个可以图片…

35.基于SpringBoot + Vue实现的前后端分离-在线考试系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的在线考试系统设计与实现管理工作系统…

Netty学习——源码篇6 Pipeline设计原理 备份

1 Pipeline设计原理 在Netty中每个Channel都有且仅有一个ChannelPipeline与之对应&#xff0c;它们的组成关系如下图&#xff1a; 通过上图可以看到&#xff0c;一个Channel包含了一个ChannelPipeline&#xff0c;而ChannelPipeline中又维护了一个由ChannelHandlerContext组成的…

HTTP工具类封装与http请求响应

一、前言 在Java web系统中经常需要与外部接口进行对接&#xff0c;比较多的方式就是是http的方式。在springboot中&#xff0c;我们可以直接使用封装的feign如&#xff1a;我们去请求微信的接口&#xff0c;定义一个client客户端&#xff0c;使用feign框架去请求就可以。但是…

全志A33编译踩坑!

领导给了个新sdk。然后开编。 编译的标准流程是这样 cd lichee ./build.sh config 这还得了&#xff0c;每次都选很烦&#xff08;虽然只需要选一次&#xff09;&#xff0c;于是新写法是这样 ./build.sh -p sun8iw5p1_android -k linux-3.4 -b evb 果断提示 ERROR: inv…

[深度学习]yolov8+streamlit搭建精美界面GUI网页设计源码实现三

【设计思路介绍】 为了使用YOLOv8和Streamlit搭建一个精美的界面GUI网页&#xff0c;你需要遵循几个关键步骤。以下是一个简化的流程&#xff0c;帮助你设计并实现这一目标&#xff1a; 1. 环境准备 安装YOLOv8 YOLOv8是一个先进的实时目标检测模型。你需要先下载并安装YOL…

Excel双击单元格后弹窗输入日期

Step1. 在VBE界面新建一个窗体(Userform1),在窗体的工具箱的空白处右键,选中添加附件,勾选Calendar control 8.0,即可完成日历的添加。 PS:遗憾的是, Office 64 位没有官方的日期选择器控件。唯一的解决方案是使用Excel 的第三方日历。 参考链接:How to insert calen…

2024最新最全Selenium自动化测试面试题!

1、什么是自动化测试、自动化测试的优势是什么&#xff1f; 通过工具或脚本代替手工测试执行过程的测试都叫自动化测试。 自动化测试的优势&#xff1a; 1、减少回归测试成本 2、减少兼容性测试成本 3、提高测试反馈速度 4、提高测试覆盖率 5、让测试工程师做更有意义的…

vue echarts 记录一个带tab切换的echarts页面 切换的时候如果有一个tab里的echarts没有数据 该如何清空echarts图的数据的问题

<template><div class"app-container"><el-form :model"queryParams" ref"queryForm" size"small" v-show"showSearch" label-width"85px"><el-form-item label"园所名称" prop&q…

Matlab从入门到精通课程

教程介绍 MATLAB是美国MathWorks公司出品的商业数学软件&#xff0c;用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 学习地址 链接&#xff1a;https://pan.baidu.com/s/1PxGarBwQusMzwPVqcE…