flutter 专题 五十六 Google 2020开发者大会Flutter专题
由于疫情的原因,今年的Google 开发者大会 (Google Developer Summit) 在线上举行,本次大会以“代码不止”为主题,全面介绍了产品更新以及一系列面向本地开发者的技术支持内容。我比较关注的是移动开发,在本次大会上,关于Flutter 主题的演讲主要从 Flutter 性能方面优化和新功能进行展开。
作为全球增长速度第二的开源项目,越来越多国内开发者使用 Flutter 实现跨平台开发,包括腾讯英语君团队、阿里闲鱼团队等等。其在 开放性上的进步,得益于开源社区、生态建设、对 Web 的支持。
有兴趣的读者可以通过Google Developer官网进行学习:Google Developer官网
下面我们就来看一下这些新功能和性能上的优化。
Flutter 性能优化
首先为我们带来演讲的是Google 软件工程师李宇骞,他是Flutter 团队的一位软件工程师,主要专注于提升其性能。下面是具体的演讲内容:
2019 下半年,Flutter 团队共收到 23 个量化的性能提升;2020 上半年,Flutter 团队共收到 27 个量化的性能提升。2020 上半年 Flutter 团队共收到来自 78 位开发者的 49 个性能改进。
工具的性能十分重要,性能测试也同样至关重要,拥有良好的性能测试可以:
- 快速重现问题;
- 迭代和验证解决方案;
- 提供数据,激励进一步的工作并防止倒退。
通常,能耗与渲染速度相关,每一帧渲染时间越长则能耗就越高,但能耗并不能衡量渲染速度,因为在某些情况下渲染速度快也可能会导致能耗升高,渲染速度慢也可能不耗能。
CPU 上运行时间虽然短,但由于新的算法利用了更多的 GPU 核心,所以 GPU 能耗反而增加;有些 CPU 上的任务被别的 I/O 或 GPU 任务阻塞,进行了长时间的等待,而等待的时间内并无过多能耗。
因此,在速度之外增加能耗测试是十分必要的。因为 Flutter 团队在 GitHub 上收到的大部分能耗问题都和 iOS 相关,所以此次 Flutter 首先加入了 iOS 的能耗测试,Android 的能耗测试工具会于后续加入。
开发者可以使用 Flutter Gallery App 在 Timeline 中查看 CPU/GPU 的使用率,也可以用集成测试自动检测 CPU/GPU 的使用率。
Flutter 还新加入了 SkSL 着色器编译预热功能,来帮助开发者消除着色器编译卡顿。如果一个 Flutter 程序第一次渲染某类动画时出现明显的卡顿,但是之后渲染这些动画时,卡顿完全消失,那么这就很可能是着色器编译卡顿。开发者可以使用 --trace-skia,然后检查 Timeline 来确认是否为着色器卡顿。
值得一提的是,SkSL 可以实现自动化生成与测试,这对于需要持续更新的 Flutter App 来说,可以节省很多的人力。
内存和包体积的测试工具
接下来,是由Flutter 用户体验研究员侯悠扬带来的测试工具专题。侯悠扬于 2017 年加入 Google,并于 2019 年加入 Flutter 团队。她是 Flutter 团队一名用户体验研究员,关注提升 Flutter 产品和开发工具的程序员体验。
此次,Flutter 团队更新了Dart开发工具。Dart 开发工具是面向 Flutter 和 Dart 开发人员的工具套件,包括如下一些小工具:
- 布局检查(Inspector)
- 性能调试(Performance)
- 内存调试(Memory)
- 网络调试(Network)
- 包体积调试(App Size)
- 调试器(Debugger)
- 日志(Logging)
连接上设备然后运行Flutter应用,点击Android Studio底部工具栏中的【Open DevTools】按钮即可开启调试功能。
内存调试器功能
Flutter的内存调试器提供如下功能:
- 事件窗格(Dart 和 Android 内存)
- 手动和自动快照(snapshot)和垃圾回收(GC)
- 内存分析
- 内存堆分配累加器(Heap Allocation Accumulators)
- 通过命令行界面将内存统计信息到处到 JSON 文件
内存测试
内存测试提供如下功能:
- 通过 ADB 交互直接进行内存测试
- Dart 开发工具内存测试
- iOS 内存测试
更多信息可以通过这篇由 Flutter 工程师撰写的文章进行了解:怎么进行Flutter内存测试
包体积调试器功能
包体积调试器提供如下功能:
- 可视化了应用程序的总大小,包括功能级别的 Dart AOT 快照;
- 分析快照和应用包(APK,IPA 等);
- 分析快照或应用程序包(APK,IPA 等)的差异;
- 查看软件包级别的应用大小归因数据。
Pigeon与Flutter混合开发
什么是Pigeon
在早期的hybird开发模式中,前端和Native交互时需要native双端为JS提供接口。这种情况下如何规范命名,参数等就成了一个问题,如果单独维护一份协议文件,三端依照协议文件进行开发,很容易出现协议更改后,没有及时同步,又或者在实际开发过程没有按照规范,可能导致各种意外情况。
同样,在Flutter插件包的开发中,因为涉及到Native双端代码开发能力,Dart侧暴露统一的接口给使用者,也会出现同样的问题,此时Pigeon应运而生,Pigeon是Flutter官方推荐插件管理工具,可以使用来解决和优化 Native 插件开发上 platform channel 相关的问题。
Flutter官方提供的Pigeon插件,通过dart入口,生成双端通用的模板代码,Native部分只需通过重写模板内的接口,无需关心methodChannel部分的具体实现,入参,出参也均通过生成的模板代码进行约束。接口新增,或者参数修改,只需要在dart侧更新协议文件,生成双端模板,即可达到同步更新,有效的避免了参数修改,参数新增带来的双端代码不同步的问题,下面是Pigeon工作原理示意图。
下面是Pigeon给出的示例:
可以看到接入Pigeon后整体代码简洁了不少,而且规范了类型定义。
Pigeon接入
接下来我们看一下如何从零接入Pigeon。截止目前,Pigeon已经发布了0.1.15版本,如下图所示。
首先,新建一个名为testpigeon的Flutter项目,打开项目的pubspec.yaml文件,并添加如下依赖代码。
dependencies:pigeon: ^0.1.15
然后,按照官方的要求在项目目录下新建一个pigeons目录,作为存放dart侧的入口文件,内容为接口、参数、返回值的定义等,以及后面通过pigeon的命令,生产native端代码。接下来,新建一个message.dart 文件,并添加如下。
import 'package:pigeon/pigeon.dart';class SearchRequest {String query;
}class SearchReply {String result;
}@HostApi()
abstract class Api {SearchReply search(SearchRequest request);
}
在上面的message.dart 文件中,通过 @HostApi() 注解标示了通信对象和接口,之后我们只需要执行如下命令,就可以生成对应代码到工程中。
flutter pub run pigeon --input pigeons/message.dart
其实上面的命令是下面命令的简写方式:
flutter pub run pigeon --input pigeons/message.dart --dart_out lib/pigeon.dart --objc_header_out ios/Runner/pigeon.h --objc_source_out ios/Runner/pigeon.m --java_out android/app/src/main/java/Pigeon.java --java_package "com.xzh.testpigeon"
命令的参数的含义如下:
- –input:引入了我们创建的 message.dart 文件;
- –dart_out:输出了 dart 模板文件;
- –objc_header_out 和 --objc_source_out 输出了 object-c 文件;
- –java_out 输出了 java 文件;
命令执行后 dart 文件输出到 lib 目录下, object-c 文件输出到了 ios/Runner 目录下,java 文件输出到指定的 com.xzh.testpigeon" 包名路径下,之后就可以开始正式接入。然后我们分别使用Android Studio和Xcode打开原生工程代码。
Android 工程代码
使用Android Studio打开Flutter项目的原生Android工程,生成的代码如下:
// Autogenerated from Pigeon (v0.1.15), do not edit directly.
// See also: https://pub.dev/packages/pigeonpackage com.xzh.testpigeon;import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import java.util.ArrayList;
import java.util.HashMap;/** Generated class from Pigeon. */
@SuppressWarnings("unused")
public class Pigeon {/** Generated class from Pigeon that represents data sent in messages. */public static class SearchReply {private String result;public String getResult() { return result; }public void setResult(String setterArg) { this.result = setterArg; }HashMap toMap() {HashMap<String, Object> toMapResult = new HashMap<>();toMapResult.put("result", result);return toMapResult;}static SearchReply fromMap(HashMap map) {SearchReply fromMapResult = new SearchReply();Object result = map.get("result");fromMapResult.result = (String)result;return fromMapResult;}}/** Generated class from Pigeon that represents data sent in messages. */public static class SearchRequest {private String query;public String getQuery() { return query; }public void setQuery(String setterArg) { this.query = setterArg; }HashMap toMap() {HashMap<String, Object> toMapResult = new HashMap<>();toMapResult.put("query", query);return toMapResult;}static SearchRequest fromMap(HashMap map) {SearchRequest fromMapResult = new SearchRequest();Object query = map.get("query");fromMapResult.query = (String)query;return fromMapResult;}}/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/public interface Api {SearchReply search(SearchRequest arg);/** Sets up an instance of `Api` to handle messages through the `binaryMessenger` */static void setup(BinaryMessenger binaryMessenger, Api api) {{BasicMessageChannel<Object> channel =new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.Api.search", new StandardMessageCodec());if (api != null) {channel.setMessageHandler((message, reply) -> {HashMap<String, HashMap> wrapped = new HashMap<>();try {@SuppressWarnings("ConstantConditions")SearchRequest input = SearchRequest.fromMap((HashMap)message);SearchReply output = api.search(input);wrapped.put("result", output.toMap());}catch (Exception exception) {wrapped.put("error", wrapError(exception));}reply.reply(wrapped);});} else {channel.setMessageHandler(null);}}}}private static HashMap wrapError(Exception exception) {HashMap<String, Object> errorMap = new HashMap<>();errorMap.put("message", exception.toString());errorMap.put("code", exception.getClass().getSimpleName());errorMap.put("details", null);return errorMap;}
}
上面生成的 Pigeon.java 代码中包含了 Api 接口用于开发者实现交互逻辑,同时开发者可以通过 SearchRequest 获取 dart 发送过来的请求,通过 SearchReply 返回数据给 dart 。然后,还需要在Android的入口文件MainActivity 中实现 Api 接口来完成数据交互,代码如下。
public class MainActivity extends FlutterActivity {private class MyApi implements Pigeon.Api {@Overridepublic Pigeon.SearchReply search(Pigeon.SearchRequest request) {Pigeon.SearchReply reply = new Pigeon.SearchReply();reply.setResult(String.format("Hi %s!", request.getQuery()));return reply;}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);Pigeon.Api.setup(getFlutterView(), new MyApi());}
}
首先,我们继承 Pigeon.Api 实现了 MyApi 对象,然后在 search() 方法中通过 request.getQuery() 获取 dart 的请求数据,并且通过 Pigeon.SearchReply 的 setResult 返回 数据给dart 端,最后通过Pigeon.Api.setup(getFlutterView(), new MyApi())
启动。
iOS
使用Xcode打开Flutter项目的iOS工程,把生成的 pigeon.h 和 pigeon.m 文件 link 到 Xcode 工程里,之后如下代码所示在 AppDelegate.h 引入 Api 协议。
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "pigeon.h"@interface AppDelegate : FlutterAppDelegate<Api>@end
接下来,在 AppDelegate.m 中实现 search 接口,并在收到的 dart 消息后基于回复,最后调用 ApiSetup()方法将完成注册。
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"@implementation AppDelegate- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[GeneratedPluginRegistrant registerWithRegistry:self];// Override point for customization after application launch.FlutterViewController* controller =(FlutterViewController*)self.window.rootViewController;ApiSetup(controller.binaryMessenger, self);return [super application:application didFinishLaunchingWithOptions:launchOptions];
}-(SearchReply *)search:(SearchRequest*)input error:(FlutterError **)error {SearchReply* result = [[SearchReply alloc] init];result.result = [NSString stringWithFormat:@"%s%@","Hi ",input.query];return result;
}@end
Dart测试
最后我们在 Dart 代码中新建一个测试的代码,如下所示。
import 'pigeon.dart';void main() {testWidgets("test pigeon", (WidgetTester tester) async {SearchRequest request = SearchRequest()..query = "Aaron";Api api = Api();SearchReply reply = await api.search(request);expect(reply.result, equals("Hi Aaron!"));});
}
Flutter 在阿里巴巴的应用
首先,主持人为我们介绍了Flutter的历史,介绍围绕美观、高效、流程和开放等几个方面来介绍Flutter。
接下来,阿里巴巴的无线技术专家门柳介绍Flutter在阿里巴巴的应用,闲鱼是阿里巴巴Flutter技术实践的先驱,也是国内最早尝试Flutter技术的大型互联网公司,而阿里巴巴旗下的淘宝也不甘示弱,也在某些模块结成Flutter,不过大多是业务级别的模块,而没有像闲鱼那样大规模使用。我们可以从下图看到Flutter在阿里巴巴的使用情况。
那为什么,这么多的移动应用开始使用Flutter来进行开发呢?首先,让我们来了解下跨平台技术的发展历程。
可以发现,移动跨平台开发经历了大约四个阶段:
- 早期的WebView加载方案
- 原生API桥接的Hybrid方案
- 原生渲染方案(Web语法+原生UI)
- 自绘渲染(独立布局/渲染)
而Flutter就是采用的自绘渲染方案,有兴趣的童鞋可以研究以下Flutter的架构。为什么选择Flutter进行跨平台应用开发呢,下面是Flutter所具有的一些优势:
不过,Flutter也不是万能的,Flutter目前处于快速迭代的阶段,所以保险起见,我们只在一些常规的业务开发和模块化的UI界面开发和部分游戏中使用Flutter。
总结起来,就是在一些富交互类应用和新型的应用中使用Flutter,对于视频、直播等渲染要求高的则继续使用原生进行开发。
那使用Flutter进行应用开发时,有哪些经验和问题需要注意呢?下图显示了阿里巴巴在使用Flutter进行应用开发时遇到的一些问题,大家使用时需要规避。
首先遇到的问题是,由于Flutter使用的是Dart进行开发,无疑增加了开发者的学习成本。其次,对于大型应用来说,如何保证代码质量,如何在多个平台运行自动化测试脚本也是一个问题;并且由于Flutter作为一门新的技术,如何快速的将老得业务迁移过来也是大家需要考虑的问题。总结一下,就是调试、测试、状态管理、缓和导航栈管理、跨平台兼容以及如何寻找解决方案的问题。
尽管Flutter已经提供了很多的工具,但是如何将它融入到阿里巴巴的客户端开发工作流中,是大家需要考虑的问题。
首先,为了提升开发效率,降低初期的接入成本,我们将Flutter Toolkit融入到Alibab DevOps工作流中,并自研了一些工具、打包和发布平台以及搭建调试环境。接下来,我们基于现存的技术积累,研发了一些中间件。
下面来看一个实例,即如何解决多图列表页面的内存占用问题。这类问题的特征如下:
- 页面很长,图片很多,首次加载时间很长
- 大量图片同时加载并生成纹理,内存飙升
- Sliver中每项Cell拆分粒度很大,单个Cell占用多屏,难以回收
对于列表Flutter列表内存回收的问题,大家可以阅读 细化 Flutter List 内存回收,解决大 Cell 问题这篇文章。
对于上面的多图长列表的内存问题,我们可以从以下几个方面着手进行优化:
- 拆分Cell,使每一项变得更小
- 根据坐标判断图片是否在屏幕内,进而进行图片的懒加载和回收
- 提前获取图片的宽高大小,减少布局和重绘
- 以图片为单位进行纹理回收,而不是Sliver中的每项Cell为单位
- 外接原生图片库,实现共享本地缓存
最后,我们来看一下Flutter在阿里巴巴的体系化建设。首先,Flutter的体系化建设主要从基础能力建设、研发平台和可持续迭代等几个方面着手。
下面是Flutter在阿里巴巴平台建设的具体的一些方案。
目前,Flutter在阿里巴巴已经经过了大规模的应用,并且我们自己的技术体系建设也在稳步推荐中,后面会将建设的一些成果通过社区分享出来。
附: Google 开发者大会
相关文章:
flutter 专题 五十六 Google 2020开发者大会Flutter专题
由于疫情的原因,今年的Google 开发者大会 (Google Developer Summit) 在线上举行,本次大会以“代码不止”为主题,全面介绍了产品更新以及一系列面向本地开发者的技术支持内容。我比较关注的是移动开发,在本次大会上,关…...
93. 后台线程与主线程更新UI Maui例子 C#例子
在.NET MAUI开发中,多线程是常见的需求,但UI更新必须在主线程上执行。今天,我们来探讨一个简单而优雅的解决方案:MainThread.InvokeOnMainThreadAsync。 一、背景 在跨平台应用开发中,后台线程常用于执行耗时操作&am…...
5.运输层
5. 运输层 1. 概述 第2~4章依次介绍了计算机网络体系结构中的物理层、数据链路层和网络层,它们共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信然而在计算机网络中实际进行通信的真正实体,是位于通信两端主机中的…...
ActiveMQ 可靠性保障:消息确认与重发机制(二)
ActiveMQ 重发机制 重发机制的原理与触发条件 ActiveMQ 的重发机制是确保消息可靠传输的重要手段。当消息发送到 ActiveMQ 服务器后,如果消费者由于某些原因未能成功处理消息,ActiveMQ 会依据配置的重发策略,将消息重新放入队列或主题中&am…...
Vue+tdesign t-input-number 设置长度和显示X号
一、需求 Vuetdesign t-input-number 想要设置input的maxlen和显示X号 二、实现 t-input,可以直接使用maxlength和clearable属性 <t-input v-model"value" clearable maxlength10 placeholder"请输入" clear"onClear" blur&q…...
机器学习|通过线性回归了解算法流程
1.线性回归引入 2.决策函数 3. 损失函数 4.目标函数 5.目标函数优化问题 6.过拟合 7.正则化...
两向量平行公式、向量与平面平行公式、两平面平行公式;两向量垂直公式、向量与平面垂直公式、两平面垂直公式
目录 一、两向量平行公式 二、向量与平面平行公式 三、两平面平行公式 四、两向量垂直公式 五、向量与平面垂直公式 六、两平面垂直公式 观察与总结 一、两向量平行公式 二、向量与平面平行公式 三、两平面平行公式 四、两向量垂直公式 五、向量与平…...
vscode 个性化
vscode 个性化 设置 吸顶效果 使用前使用后 设置方法 VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行 插件 代码片段分享 - CodeSnap 使用方式 CtrlShiftP输入CodeSnap 唤起插件选择代码 行内报错提示 - Error Lens 使用前使用后 VSCode Error Lens插件介绍&…...
OpenHarmony-简单的HDF驱动
学习于:https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-hdf-manage.md 首先,OpenHarmony系统里的HDF(Hardware Driver Foundation)驱动框架,已经规范设备驱动的模型、设备节点的配置与统一的…...
Copilot重磅更新:引用文件夹创建Word文档
大家好,AI技术笔记为您带来一则好消息: 根据广大用户的反馈,Microsoft 365 Copilot在Word中的引用能力全面升级啦! 不管是撰写、审阅还是定稿文档,现在你可以更快、更高效地引用更多资料! ✨三大重磅改进…...
SQL Server数据库提权的几种方法——提权教程
SQL Server数据库提权的几种方法——提权教程 一、简介 在利用系统溢出漏洞没有效果的情况下,可以采用数据库进行提权。 数据库提权的前提条件: 1、服务器开启数据库服务 2、获取到最高权限用户密码 (除Access数据库外,其他数据库基本都存在数据库提权的可能) 二、使用x…...
解决在Mac上无法使用“ll”命令
在 macOS 上,ll 命令是一个常见的别名,它通常是指向 ls -l 的。但是,如果你看到 zsh: command not found: ll,这意味着你当前的 zsh 配置中没有设置 ll 作为别名。 解决方法: 1. 使用 ls -l 命令 如果只是想查看目录…...
Dockerfile最佳实践:构建高效、安全的容器镜像
一、前言 Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有指令,每一条指令构建一层镜像。在日常开发中我们常常需要自己编写Dockerfile来构建镜像,而构建一个精巧、实用且高品质的镜像对运行环境来说尤为重要。下面我们来排一排如何构建这样的镜像。 二、目…...
mac电脑pytest生成测试报告
时隔了好久再写代码,感觉我之前的积累都白费了,全部忘记了,看来每一步都有记录对于我来说才是最好的。 最近又要重新搞接口自动化,然而是在mac电脑,对于我长期使用windows的人来说真的是个考验,对此次过程…...
鸿蒙 应用开发 项目资源结构及资源访问
三层工程结构 模块分类 使用...
C#学习第20天:垃圾回收
什么是垃圾回收? 定义:垃圾回收是一种自动内存管理机制,负责回收不再使用的对象所占用的内存。目的:通过自动化内存回收,减少内存泄漏的风险,并简化开发者的工作。 垃圾回收的核心概念 1. 垃圾回收器的工…...
C#学习笔记 项目引用添加异常
这个问题出现多次了 我觉得有必要记录一下 场景 同一个解决方案下添加了多个项目 我想在单元测试项目中引用一下项目1,按照步骤:添加引用- 项目- 浏览- 在指定目录下找到项目的工程文件XXXSystem.csproj- 确定 然后就触发了异常 解决方案 首先 清理解决…...
使用模块中的`XPath`语法提取非结构化数据
想要在代码中使用Xpath进行处理,就需要模块lxml 模块安装 pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simplelxml的使用 使用lxml转化为Element对象 from lxml import etreetext <div> <ul> <li class"item-1"><a …...
复杂度和顺序表(双指针方法)
目录 目录 目录 前言: 一、时间复杂度和空间复杂度 1.1概念 1.2规则 二、顺序表 2.1静态顺序表 2.2动态顺序表 三、双指针法 四、总结 前言: 时间复杂度和空间复杂度是用于判断算法好坏的指标,程序性能的核心指标。时间复杂度主要衡…...
day006-实战练习题-参考答案
老男孩教育-99期-实战练习题 1. 你作为"老男孩教育99期云计算"新晋运维工程师,在入职首日遭遇紧急事件: "生产环境3台Web服务器突发性能告警,技术总监要求你立即完成: 快速建立故障诊断工作区收集关键系统指标分…...
批量删除OpenStack实例
在Linux终端实现批量删除OpenStack实例,支持并发删除、安全确认、重试机制、优先清理运行中实例 #!/bin/bash # # 增强版 OpenStack 删除实例脚本 # 功能:支持并发删除、安全确认、重试机制、优先清理运行中实例 # 更新:2025年4月30日 # ##…...
楼宇智能化一、二章【期末复习】
一章、楼宇概述 智能建筑的定义:以建筑物为平台,基于对各类智能化信息的综合应用,集架构、系统、应用、管理及优化组合为一体,具有感知、传输、记忆、推理、判断和决策的综合智慧能力,形成以人、建筑、环境互为协调的整合体,为人们提供安全、高效、便利及可持续发展功能…...
三生原理与西方哲学的具体对比?
AI辅助创作: 一、本体论差异 生成论与构成论的分野 三生原理以《周易》“太极生两仪,两仪生四象,四象生八卦”、《道德经》“道生一,一生二,二生三,三生万物”为基础,构建动态层级生成的宇…...
呼叫中心座席管理系统:智能升级,高效服务
在数字化转型加速的今天,客户服务体验已成为企业竞争力的核心要素。传统 呼叫中心系统 依赖硬件设备、人工操作的模式已无法满足高效、智能、灵活的现代企业需求。畅信达呼叫中心 座席管理系统 V5.0应运而生,以WEBRTC软电话接入、智能座席辅助、知识库管…...
PCB设计实战技巧宝典:从库管理到布线优化的全流程解析
知识点1【PCB设计流程】 器件 符号 封装 (3D模型 实物图 ) 流程介绍 1、如果没有需要的的库,先画库:器件,符号,封装 2、新建工程,放置器件在原理图 3、原理图转PCB 4、导出ROM和Gerber…...
微信小程序 XSS 防护知识整理
场景1:用户输入表单(如评论框) 错误做法:直接渲染未过滤的用户输入 // WXML <view>{{ userInput }}</view>// JS(用户输入了恶意内容) Page({data: { userInput: <script>alert("…...
平衡截断(Balanced Truncation)—— MTALAB 和 Python 实现
平衡截断balreal 算法原理平衡截断过程求解 HSV 为什么不使用定义而是使用 Cholesy 和SVD 分解? MATLAB 实践Python 实现 先验知识:可控性 Gramian W c W_c Wc、可观性 Gramian W o W_o Wo 以及 Hankel 奇异值(HSV) σ i \s…...
机器手电机驱动器小体积解决方案
市场背景 随着工业4.0与人工智能技术的深度融合,智能机器人正加速渗透至医疗、物流、制造及服务等核心领域。据行业分析显示,2023年全球协作机器人市场规模同比增长23%,其中高精度关节驱动与小型化硬件设计成为技术迭代的关键需求。然而&…...
(数智化)采购管理系统平台开发费用
随着招标采购数智化升级加速,采购管理系统平台开发费用成为企业关注的焦点——从几十万到几百万不等,那么开发成本差异的背后藏着怎样的技术逻辑与价值密码呢?采购管理系统研发商郑州信源信息技术股份有限公司根据行业特点及客户实际实践总结…...
K8S Secret 快速开始
一、什么是 Secret? Kubernetes(K8s)中的 Secret 是一种用于存储和管理敏感信息(如密码、令牌、证书、API 密钥等)的资源对象。它避免了将敏感数据明文写入配置文件、镜像或代码中,提供了一种更安全的方式…...
TEN:开启实时语音交互的下一代AI Agent引擎
在AI技术飞速发展的今天,语音交互正成为人机交互的重要方式。传统的文本对话已无法满足用户对自然、高效沟通的需求,而TEN开源框架的出现,为开发者提供了构建超低延迟、可听可说的AI Agent的终极解决方案。 一、TEN的核心优势 超低延迟实时交…...
DeepSeek驱动的金市情绪量化:NLP解析贸易政策文本的情绪传导路径
【AI观察】政策信号与市场情绪的量化关联 基于自然语言处理技术对全球财经文本的情绪分析显示,4月30日亚盘时段现货黄金价格波动率较前日下降12.3%,与技术面修正指标呈现强相关性。特政府最新关税政策调整引发市场风险偏好指数(RPIÿ…...
JVM快速入门
目录 前言: 1.JVM的位置 2.JVM的体系结构 3.类加载器 类加载器中的一些方法和细节: 4.双亲委派机制 5.沙箱安全机制 概念 原理 Java 沙箱安全机制 应用场景 6.Native 7.方法区: 8.PC寄存器 9.栈 10.三种JVM HotSpot VM OpenJ9 VM Zin…...
spring--事务详解
spring事务 什么是事务 我们常说的事务,一般指数据库事务。 数据库事务是指 一个逻辑工作单元中执行的一系列(数据库操作),要么一起成功,要么一起失败 当工作单元中的所有操作全部正确完成时,工作单元的…...
CSS实现DIV水平与垂直居中方法总结
大家好,欢迎来到程序视点!我是你们的老朋友.小二! CSS实现DIV水平与垂直居中方法总结 一、水平居中方案 标准方法 .center-div {margin-left: auto;margin-right: auto; }关键点:必须声明DOCTYPE(推荐XHTML 1.0 Tran…...
AI 助力 Python:长时序植被遥感动态分析与生态评估
技术点目录 Python遥感数据处理基础及AI大模型应用技巧常用共享数据资源介绍AI辅助下地球科学数据处理方法及python实现AI辅助下植被参数遥感反演基本原理及python实现AI辅助下地球科学数据分析方法及python实现AI辅助下植被物候提取与分析实践应用AI辅助下植被时空动态分析及p…...
卫星变轨轨迹和推力模拟(单一引力源)MATLAB
代码说明: 常量定义:定义了万有引力常数、地球和月球的质量、半径以及地月平均距离。初始状态设置:设置卫星的初始位置、速度和姿态,以及月球的初始位置。模拟循环:在循环中计算地球和月球对卫星的引力,模…...
2025华东杯B题华东杯数学建模思路代码成品讲解工序安排问题
完整内容请看文章最下面的推广群 我将展示完整的文章、代码和结果 工序安排问题 摘要 本文研究的核心是制造业中的工序安排优化问题,源自实际生产管理中常见的资源分配挑战。问题背景设定为一家拥有100名工人和三条相同服装生产线的成衣制造厂,涉及裁…...
Python的赋值操作都是引用吗?
Python的赋值操作都是引用吗? 一言以蔽之:Python的赋值本质都是引用传递,但不可变对象的表现类似于值传递,这是由对象不可变性造成的效果。(我非常确信这篇笔记说的内容都是正确的,这篇笔记是deepseekv3的…...
学习influxDB的安装和使用
influxDB的使用场景 nfluxDB 是一种时序数据库,时序数据库通常被用在监控场景,用来收集各个节点采集到的监控指标,以及监控指标产生的时间点.比如我们收集的主机的监控数据,可以通过查询语句,统计查询过去30分钟内cpu的平均使用率是多少. 相比关系型数据库与时序数…...
LeetCode209_长度最小的子数组
LeetCode209_长度最小的子数组 标签:#数组 #二分查找 #前缀和 #滑动窗口Ⅰ. 题目Ⅱ. 示例0. 个人方法:滑动窗口 标签:#数组 #二分查找 #前缀和 #滑动窗口 Ⅰ. 题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足…...
uniapp 实现时分秒 分别倒计时
效果 <view class"issue-price-countdown"> <CountDown :endTimestamp"1745996085000"></CountDown> </view> 引入组件 import CountDown from /components/CountDown.vue; <template> <view class&qu…...
ubuntu下一些环境配置
1、qhull sudo apt install qhull-bin libqhull-dev 2、cmake wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo "deb [signed…...
el-check-box多选框和el-select下拉框组合
<template><div><el-selectv-model"selectedValues"multiplecollapse-tagsplaceholder"请选择电压等级"change"handleChange"><el-option key"all" value"all" class"select-all-option">…...
SPSS PCA+判别分析
1, 主成分分析PCA 我们只要对数化的变量数据: (1)对数据进行标准化处理: 选择【分析】—【描述统计】—【描述】 添加要标准化的变量,勾选【将标准化值另存为变量(Z)】,再点确定 SPSS软件本身不…...
【阿里云大模型高级工程师ACP习题集】2.7 通过微调增强模型能力 (下篇)(⭐️⭐️⭐️ 重点章节!!!)
习题集: 【单选题】在阿里云大模型微调中,以下关于预训练和微调的说法,错误的是?( ) A. 预训练使用自监督/无监督学习方式 B. 微调通常在大规模通用数据集上进行 C. 预训练模型可以为下游任务提供初始模型 D. 微调能让模型适应具体的下游任务 【多选题】LoRA微调中,低秩…...
ag-grid-react 列表导出csv列表getDataAsCsv (自定义导出列表配置)自定义新增,修改导出内容
1.ag-grid-react getDataAsCsv 新增导出字段 方法:临时添加列再导出 你可以通过 columnApi.setColumnDefs() 临时添加需要导出的字段,然后再调用 getDataAsCsv,导出后再恢复原来的列。 import { useRef } from react; import { AgGridReac…...
深度解析:Vue.js 性能优化全景指南(从原理到实践)
前言 随着 Vue.js 应用复杂度提升,性能问题逐渐成为制约用户体验的瓶颈。本文将系统性地剖析 Vue.js 性能优化的 核心原理、关键技巧、工具链支持,并通过真实案例演示如何提升大型应用的运行时性能与加载效率。 一、渲染层优化:减少不必要的…...
Linux -- 操作系统
一、冯•诺依曼体系结构 1、概念 # 在计算机发展历程中,核心作用就是解决人类问题。为了实现这一目标,计算机系统需具备特定结构和功能。 首先,计算机要配备输入设备,如鼠标、键盘、摄像头、话筒、磁盘(文件读取&…...
(初探)强化学习路径规划的理论基础与代码实现
一、强化学习路径规划的核心理论 1.1 马尔可夫决策过程(MDP)框架 理论基础: 路径规划问题可以建模为马尔可夫决策过程(Markov Decision Process, MDP),由五元组(S, A, P, R, γ)定义。其中,S&…...