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…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...