Flutter开发进阶之瞧瞧BuildOwner
Flutter开发进阶之瞧瞧BuildOwner
上回说到关于Element Tree的构建还缺最后一块拼图,build的重要过程中会调用_element!.markNeedsBuild();
,而markNeedsBuild
会调用owner!.scheduleBuildFor(this);
。
在Flutter框架中,BuildOwner
负责管理构建过程,它持有当前构建周期的所有相关信息,并协调Widget
到Element
的转换过程。
让我们看看BuildOwner
在Element
中的定义。
/*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')elseErrorHint('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 elementin _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 elementin _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 keyin 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
,它是持有Widget
、State
、BuildOwner
的实例,它可以包含其他子Element
形成Tree,Element
通过State
的状态管理去进行对应的生命周期管理,同个Tree下Element
对应一个根BuildOwner
,_owner = parent.owner;
它负责协调构建过程,当Element添加进_dirtyElements
中时,Flutter循环调用的WidgetsBinding.drawFrame
(WidgetsFlutterBinding.ensureInitialized()
或runApp()
后会激活的循环)会重新构建Tree渲染到屏幕上。
以上完成build
闭环。
相关文章:

Flutter开发进阶之瞧瞧BuildOwner
Flutter开发进阶之瞧瞧BuildOwner 上回说到关于Element Tree的构建还缺最后一块拼图,build的重要过程中会调用_element!.markNeedsBuild();,而markNeedsBuild会调用owner!.scheduleBuildFor(this);。 在Flutter框架中,BuildOwner负责管理构建…...

大量免费工具使用(提供api接口)
标题: 免费工具集使用 - 简化你的任务 介绍: 在数字化时代,我们经常需要使用各种工具来完成各种任务。本文将介绍一个免费工具集,它提供了多种实用工具,帮助简化你的任务。这些工具可以在网站 https://tool.kertennet.com 上找到…...

网络探测工具Nmap介绍
1. Nmap简介 Nmap是一款用于网络发现和安全审计的网络安全工具。可用于列举网络主机清单、管理服务升级调度、监控主机、监控主机服务运行状况、检测目标主机是否在线和端口开放情况、侦测运行的服务类型及版本信息、侦测操作系统与设备类型等。 2. 命令大纲 3. 命令详细介绍…...

20240319-2-机器学习基础面试题
⽼板给了你⼀个关于癌症检测的数据集,你构建了⼆分类器然后计算了准确率为 98%, 你是否对这个模型很满意?为什么?如果还不算理想,接下来该怎么做? 首先模型主要是找出患有癌症的患者,模型关注的…...

0202矩阵的运算-矩阵及其运算-线性代数
文章目录 一、矩阵的加法二、数与矩阵相乘三、矩阵与矩阵相乘四、矩阵的转置五、方阵的行列式结语 一、矩阵的加法 定义2 设有两个 m n m\times n mn橘子 A ( a i j ) 和 B ( b i j ) A(a_{ij})和B(b_{ij}) A(aij)和B(bij),那么矩阵A与B的和记为AB,规定为 A B ( a 11…...

python中的__dict__
类的__dict__返回的是:类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里的, 而实例化对象的:__dict__中存储了一些类中__init__的一些属性值。 import的py文件 __dict__返回的是:__init__的…...

数学分析复习:无穷乘积
文章目录 无穷乘积定义:无穷乘积的收敛性命题:无穷乘积的Cauchy收敛准则正项级数和无穷乘积的联系 本篇文章适合个人复习翻阅,不建议新手入门使用 无穷乘积 设复数列 { a n } n ≥ 1 \{a_n\}_{n\geq 1} {an}n≥1,设对任意 …...

02 React 组件使用
import React, { useState } from react;// 定义一个简单的函数式组件 function Counter() {// 使用 useState hook 来创建一个状态变量 count,并提供修改该状态的函数 setCountconst [count, setCount] useState(0);// 在点击按钮时增加计数器的值const increment…...

你就是上帝
你就是上帝:Jv程序员,请你站在上帝或神的角度 1.万物皆有裂缝 按照西方文化(宗教神话,古希腊、古罗马等),上帝创建了人; 创建人之前,还创建了人的居所或地盘/栖息地(伊…...

Spring Cloud: openFegin使用
文章目录 一、OpenFeign简介二、Springboot集成OpenFeign1、引入依赖2、EnableFeignClients注解(1)应用(2)属性解析 3、 FeignClient(1)应用(2)属性解析(3)向…...

流畅的 Python 第二版(GPT 重译)(二)
第三章:字典和集合 Python 基本上是用大量语法糖包装的字典。 Lalo Martins,早期数字游牧民和 Pythonista 我们在所有的 Python 程序中都使用字典。即使不是直接在我们的代码中,也是间接的,因为dict类型是 Python 实现的基本部分。…...

Flutter 旋转动画 线性变化的旋转动画
直接上代码 图片自己添加一张就好了 import dart:math;import package:flutter/material.dart;import package:flutter/animation.dart;void main() > runApp(MyApp()); //旋转动画 class MyApp extends StatelessWidget {overrideWidget build(BuildContext context) {re…...

【Web应用技术基础】HTML(5)——案例1:展示简历信息
样式: 代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>展示简历信息…...

ethers.js:wallet(创建钱包,导入助记词,导入私钥)
Wallet Wallet类继承了Signer,可以使用私钥作为外部拥有帐户(EOA)的标准对交易和消息进行签名。 npm install ethers@5.4.0// 引入 import {ethers } from ethers创建新钱包 this.provider = new ethers.providers.Web3Provider(window...

面试笔记——Java集合篇
Java集合框架体系 重点:单列集合——ArrayList、LinkedList;双列集合——HashMap、ConcurrentHashMap。 List相关 数组(Array) 是一种用连续的内存空间存储相同数据类型数据的线性数据结构。 数组获取其他元素: 为什…...

在 IntelliJ IDEA 中使用 Terminal 执行 git log 命令后的退出方法
前言 IntelliJ IDEA 是一款广受欢迎的集成开发环境,它内置了强大的终端工具,使得开发者无需离开IDE就能便捷地执行各种命令行操作,包括使用 Git 进行版本控制。在 IDEA 的 Terminal 中执行 git log 命令时,由于该命令会显示项目的…...

架构整洁之道-读书总结
1 概述 1.1 关于本书 《架构整洁之道》(Clean Architecture: A Craftsman’s Guide to Software Structure and Design)是由著名的软件工程师Robert C. Martin(又称为Uncle Bob)所著。这本书提供了软件开发和架构设计的指导原则…...

蓝桥杯学习笔记(贪心)
在很久很久以前,有几个部落居住在平原上,依次编号为1到n。第之个部落的人数为 t 有一年发生了灾荒,年轻的政治家小蓝想要说服所有部落一同应对灾荒,他能通过谈判来说服部落进行联台。 每次谈判,小蓝只能邀请两个部落参…...

【无标题】如何使用 MuLogin 设置代理
如何使用 MuLogin 设置代理 使用 MuLogin 浏览器设置我们的代理,轻松管理多个社交媒体或电子商务帐户。 什么是MuLogin? MuLogin 是一款虚拟反检测浏览器,使用户能够管理多个电子商务、社交媒体和广告帐户,而无需验证码或 IP 禁…...

芒果YOLOv8改进135:主干篇GCNet,统一为全局上下文建模global context结构,即插即用,助力小目标检测,轻量化的同时精度性能涨点
该专栏完整目录链接: 芒果YOLOv8深度改进教程 芒果专栏 基于 GCNet 的改进结构,改进源码教程 | 详情如下🥇 💡本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 即插即用 结构。博客 包括改进所需的 核心结构代码 文件 论文:https://arxiv.org/a…...

全面:vue.config.js 的完整配置
vue.config.js是Vue项目的配置文件,用于配置项目的构建、打包和开发环境等。 在Vue CLI 3.0之后,项目的配置文件从原来的build和config目录下的多个配置文件,合并成了一个vue.config.js文件。这个文件可以放在项目的根目录下,用于…...

海量数据处理项目-账号微服务注册Nacos+配置文件增加
海量数据处理项目-账号微服务注册Nacos配置文件增加 导入生成好的代码 model (为啥不放common项目,如果是确定每个服务都用到的依赖或者类才放到common项目) mapper 类接口拷贝 resource/mapper文件夹 xml脚本拷贝 controller service 不拷贝 Mybatis plus配置控制…...

DNS 服务 Unbound 部署最佳实践
文章目录 安装unbound-control配置启动服务测试 参考: 官网地址:https://nlnetlabs.nl/projects/unbound/about/ 详细文档:https://unbound.docs.nlnetlabs.nl/en/latest/index.html DNS服务Unbound部署于使用 https://cloud.tencent.com/…...

力扣HOT100 - 42. 接雨水
解题思路: 动态规划 感觉不是很好想 class Solution {public int trap(int[] height) {int n height.length;if (n 0) return 0;int[] leftMax new int[n];leftMax[0] height[0];for (int i 1; i < n; i) {leftMax[i] Math.max(leftMax[i - 1], height[i…...

攻防世界-baby_web
题目信息 相关知识 使用bp进行抓包 解题过程 题目界面如下所示: 试图找index界面: 发现又跳转到http://61.147.171.105:51201/1.php页面,因此说明61.147.171.105:51201/index.php是存在的(因为笔者试了,不存在的页面会直接报…...

数据可视化基础与应用-04-seaborn库从入门到精通01-02
总结 本系列是数据可视化基础与应用的第04篇seaborn,是seaborn从入门到精通系列第1-2篇。本系列的目的是可以完整的完成seaborn从入门到精通。主要介绍基于seaborn实现数据可视化。 参考 参考:数据可视化-seaborn seaborn从入门到精通01-seaborn介绍与load_datas…...

学习 zustand
学习 zustand https://github.com/pmndrs/zustand告别繁杂的状态管理:Zustand 的简洁之道Zustand 状态库:轻便、简洁、强大的 React 状态管理工具关于 zustand 的一些最佳实践 代码库 https://gitee.com/nian_zuo_chen/learnrect/tree/master/zustand 安…...

竞赛 opencv python 深度学习垃圾图像分类系统
0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 opencv python 深度学习垃圾分类系统 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:3分创新点:4分 这是一个较为新颖的竞…...

vsto worksheet中查找关键字【关键字】获取对应的整列 union成一个range
要在 VSTO 中的工作表中查找包含特定关键字的单元格,并将这些单元格所在列合并为一个范围,可以使用以下代码:csharp using Excel Microsoft.Office.Interop.Excel;// 在工作表中查找包含特定关键字的单元格,并返回这些单元格所在…...

flask_restful规范返回值之参数设置
设置重命名属性和默认值 使用 attribute 配置这种映射 , 比如: fields.String(attributeusername) 使用 default 指定默认值,比如: fields.String(defaultsxt) from flask import Flask,render_template from flask_restful import A…...