HarmonyOS应用六之应用程序进阶一
目录:
- 1、UIAbility的冷启动和UIAbility热启动
- 2、静态资源和动态资源的访问
- 3、页面跳转
- 3.1、页面返回跳转
- 4、HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用
- 4.1、导出HAR的ArkUI组件
- 4.2、引用HAR的ArkUI组件
- 5、循环渲染
- 6、状态管理最佳实践
- 7、AppStorage的使用精细化拆分复杂状态
1、UIAbility的冷启动和UIAbility热启动
- UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。
目标UIAbility冷启动时,在目标UIAbility的onCreate()生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的onWindowStageCreate()生命周期回调中,解析调用方传递过来的want参数,获取到需要加载的页面信息url,传入windowStage.loadContent()方法。
import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window, UIContext } from '@kit.ArkUI';const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EntryAbility]';export default class EntryAbility extends UIAbility {funcAbilityWant: Want | undefined = undefined;uiContext: UIContext | undefined = undefined;onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {// 接收调用方UIAbility传过来的参数this.funcAbilityWant = want;}onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');// Main window is created, set main page for this abilitylet url = 'pages/Index';if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {url = 'pages/Page_ColdStartUp';}windowStage.loadContent(url, (err, data) => {// ...});}
}
- UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。
在应用开发中,会遇到目标UIAbility实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发onNewWant()生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理。
例如短信应用和联系人应用配合使用的场景。
1、用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。
2、用户将设备回到桌面界面,短信应用进入后台运行状态。
3、用户打开联系人应用,找到联系人张三。
4、用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。
5、由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的onNewWant()回调,而不会再走onCreate()和onWindowStageCreate()等初始化逻辑。
import { AbilityConstant, Want, UIAbility } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import type { Router, UIContext } from '@kit.ArkUI';
import type { BusinessError } from '@kit.BasicServicesKit';const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EntryAbility]';export default class EntryAbility extends UIAbility {funcAbilityWant: Want | undefined = undefined;uiContext: UIContext | undefined = undefined;// ...onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {if (want?.parameters?.router && want.parameters.router === 'funcA') {let funcAUrl = 'pages/Page_HotStartUp';if (this.uiContext) {let router: Router = this.uiContext.getRouter();router.pushUrl({url: funcAUrl}).catch((err: BusinessError) => {hilog.error(DOMAIN_NUMBER, TAG, `Failed to push url. Code is ${err.code}, message is ${err.message}`);});}}}
}
热启动是前提得有冷启动,就是应用启动后处于后台运行,当从其他位置点击进来需要进入后台运行的应用程序时就需要使用到热启动。
2、静态资源和动态资源的访问
在组件中,经常需要使用字符串、图片等资源。HSP中的组件需要使用资源时,一般将其所用资源放在HSP包内,而非放在HSP的使用方处,以符合高内聚低耦合的原则。
在工程中,常通过 r / r/ r/rawfile的形式引用应用资源。可以用 r / r/ r/rawfile访问本模块resources目录下的资源,如访问resources目录下定义的图片src/main/resources/base/media/example.png时,可以用$r(“app.media.example”)
// library/src/main/ets/pages/Index.ets
// 正确用例
Image($r('app.media.example')).id('example').borderRadius('48px')
// 错误用例
Image("../../resources/base/media/example.png").id('example').borderRadius('48px')
将需要对外提供的资源封装为一个资源管理类:
// library/src/main/ets/ResManager.ets
export class ResManager{static getPic(): Resource{return $r('app.media.pic');}static getDesc(): Resource{return $r('app.string.shared_desc');}
}
对外暴露的接口,需要在入口文件index.ets中声明:
// library/index.ets
export { ResManager } from './src/main/ets/ResManager';
3、页面跳转
其中router.pushUrl方法的入参中url的内容为:
'@bundle:com.samples.hspsample/library/ets/pages/Menu'
url内容的模板为:
'@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)'
3.1、页面返回跳转
页面返回router.back方法的入参中url说明:
如果从HSP页面返回HAP页面,url的内容为:
'pages/Index'
url内容的模板为:
'页面所在的文件名(不加.ets后缀)'
如果从HSP1的页面跳到HSP2的页面后,需要返回到HSP1的页面,url的内容为:
'@bundle:com.samples.hspsample/library/ets/pages/Menu'
url内容的模板为:
'@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)'
4、HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用
4.1、导出HAR的ArkUI组件
Index.ets文件是HAR导出声明文件的入口,HAR需要导出的接口,统一在Index.ets文件中导出。Index.ets文件是DevEco Studio默认自动生成的,用户也可以自定义,在模块的oh-package.json5文件中的main字段配置入口声明文件,配置如下所示:
{"main": "Index.ets"
}
导出ArkUI组件
ArkUI组件的导出方式与ts的导出方式一致,通过export导出ArkUI组件,示例如下:
// library/src/main/ets/components/mainpage/MainPage.ets
@Component
export struct MainPage {@State message: string = 'HAR MainPage';build() {Column() {Row() {Text(this.message).fontSize(32).fontWeight(FontWeight.Bold)}.margin({ top: '32px' }).height(56).width('624px')Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center, alignContent: FlexAlign.Center }) {Column() {Image($r('app.media.pic_empty')).width('33%')Text($r('app.string.empty')).fontSize(14).fontColor($r('app.color.text_color'))}}.width('100%').height('90%')}.width('100%').height('100%').backgroundColor($r('app.color.page_background'))}
}
HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:
// library/Index.ets
export { MainPage } from './src/main/ets/components/mainpage/MainPage';
4.2、引用HAR的ArkUI组件
HAR的依赖配置成功后,可以引用HAR的ArkUI组件。ArkUI组件的导入方式与ts的导入方式一致,通过import引入HAR导出的ArkUI组件,示例如下所示:
// entry/src/main/ets/pages/IndexSec.ets
import { MainPage } from 'library';@Entry
@Component
struct IndexSec {build() {Row() {// 引用HAR的ArkUI组件MainPage()}.height('100%')}
}
5、循环渲染
@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Row() {Column() {ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string) => item)}.width('100%').height('100%')}.height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(50)}
}
运行效果如图所示:
此次是循环遍历数据,通过@Prop监听父组件中的值,进行字体大小为50的逻辑处理。
6、状态管理最佳实践
@Observed
class Translate {translateX: number = 20;
}@Entry
@Component
struct UnnecessaryState1 {@State translateObj: Translate = new Translate(); // 同时存在读写操作,并关联了Button组件,推荐使用状态变量buttonMsg = 'I am button'; // 仅读取变量buttonMsg的值,没有任何写的操作,直接使用一般变量即可build() {Column() {Button(this.buttonMsg).onClick(() => {animateTo({duration: 50}, () => {this.translateObj.translateX = (this.translateObj.translateX + 50) % 150; // 点击时给变量translateObj重新赋值})})}.translate({x: this.translateObj.translateX // 读取translateObj中的值})}
}
没有关联任何UI组件的状态变量和没有修改过的状态变量不应该定义为状态变量,直接使用一般变量即可,否则会影响性能。
7、AppStorage的使用精细化拆分复杂状态
对AppStorage的使用,以“HMOS世界App”中共享用户信息和用户收藏信息为例,描述如何拆分状态存储。用户信息和用户收藏信息涉及的模块和界面展示如下:
- “我的”模块顶部有展示用户信息的组件“UserInfoView”,底部有展示用户收藏列表,列表卡片上需要高亮展示用户是否点赞了当前文章。
- “探索”模块首页展示技术文章列表,列表卡片上同样需要展示用户是否点赞了当前文章。
- 当两个模块中任一模块的卡片有点赞交互时,需要同步用户是否对文章点赞的状态给另一个模块。
当前项目中已经使用AppStorage存储用户信息UserData,UserData的数据结构和“UserInfoView”组件使用UserData状态展示用户信息的代码如下:
//用户信息UserData的数据结构
export interface UserData {id: string;username: string;description: string;// ...
}//在业务类中获取服务端用户信息
getUserData(): void {this.userAccountRepository.getUserData().then((data: UserData) => {//1.将用户信息数据存储到AppStorage中AppStorage.setOrCreate('userData', data);})
}//“我的”模块顶部展示用户信息的视图组件
@Component
struct UserInfoView {//2.在UI中使用@StorageLink装饰器接收AppStorage中存储的用户信息@StorageLink('userData') userData: UserData | null = null;build() {Column() {Row({ space: Constants.MIDDLE_SPACE }) {// ...Column() {//3.展示用户信息userData中的用户名Text(this.userData? this.userData.username : $r('app.string.default_login'))// ...}}// ...}// ...}
}
现在“探索“模块和“我的“模块需要共享用户的收藏列表信息,只需要共享收藏的文章id数组即可。不同模块间的状态共享考虑将其也存储在AppStorage中,有如下两种存储方案:
-
收藏信息也是用户信息的一部分,将收藏信息作为用户信息userData的一个属性,存储在当前AppStorage里key值为“userData”的变量上。
-
收藏信息单独存入AppStorage中,不与用户信息userData绑定。
第一种方案的代码实现如下:
export interface UserData {id: string;username: string;description: string;// 1. 在用户信息UserData上增加用户收藏的资源列表id信息类型定义collectedIds: string[];// ...
}//在业务类中获取服务端用户信息
getUserData(): void {this.userAccountRepository.getUserData().then((data: UserData) => {//2.将用户信息数据存储到AppStorage中AppStorage.setOrCreate('userData', data);})
}// 探索模块的文章卡片组件
@Component
export struct ArticleCardView {//3.在探索文章列表卡片上通过@StorageLink装饰器获取用户信息对象userData@StorageLink('userData') userData: UserData | null = null;@Prop articleItem: LearningResource = new LearningResource();//4.根据收藏信息数组计算当前文章是否被收藏isCollected(): boolean {return this.userData && this.userData.collectedIds.some((id: string) => id === this.articleItem.id);}//7.处理界面点赞交互逻辑:使用@StorageLink装饰器接收的userData状态子属性collectedIds被修改后,新值会同步到AppStorage中handleCollected(): void {const index = this.userData?.collectedIds.findIndex((id: string) => id === this.articleItem.id);if (index === -1) {this.userData?.collectedIds.push(resourceId);} else {this.userData?.collectedIds.splice(index, 1);}// ...}build(){ActionButtonView({//5.根据当前文章是否被用户收藏,判断收藏图标是否高亮imgResource: this.isCollected() ? $r('app.media.btn_favorites_on') : $r('app.media.btn_favorites_normal'),count: this.articleItem.collectionCount,textWidth: $r('app.float.star_icon_width')}).onClick(() => {//6.用户点击收藏图标时,调用处理收藏状态修改的函数this.handleCollected();})}
}
这种实现方案下,当用户在“UserInfoView ”组件上重新修改用户描述信息userData.description属性值时,属性值变化将同步回AppStorage中。ArkUI监听到AppStorage中key值为“userData”的值变化,随后通知所有使用了AppStorage中key值为“userData”的组件重新渲染。
在上述界面中,“我的“模块中展示用户信息的组件“UserInfoView ”会重新渲染。由于“探索”模块的文章卡片组件ArticleCardView 通过@StorageLink装饰器绑定了AppStorage中key值为“userData”的变量,所有的文章卡片组件也都会重新渲染。而这些组件与用户描述信息无关,不应该被描述信息的修改变化影响,从而导致渲染刷新。
改为使用上述第二种方案实现,代码如下:
//在业务类中获取用户信息
getUserData(): void {this.userAccountRepository.getUserData().then((data: UserData) => {//1.将用户收藏信息单独数据存储到AppStorage中AppStorage.setOrCreate('collectedIds', data.collectedIds);AppStorage.setOrCreate('userData', data);})
}// 探索模块的文章卡片组件
@Component
export struct ArticleCardView {//2.通过@StorageLink装饰器获取AppStorage中存储的收藏信息@StorageLink('collectedIds') collectedIds: string[] = [];@Prop articleItem: LearningResource = new LearningResource();//3.根据收藏信息数组计算当前文章是否被收藏 isCollected(): boolean {return this.collectedIds.some((id: string) => id === this.articleItem.id);}//6.处理界面点赞交互逻辑:使用@StorageLink装饰器接收的状态collectedIds被修改后,新值会同步到AppStorage中handleCollected(): void {const index = this.collectedIds.findIndex((id: string) => id === this.articleItem.id);if (index === -1) {this.collectedIds.push(resourceId);} else {this.collectedIds.splice(index, 1);}// ...}build(){ActionButtonView({//4.根据当前文章是否被用户收藏,判断收藏图标是否高亮imgResource: this.isCollected() ? $r('app.media.btn_favorites_on') : $r('app.media.btn_favorites_normal'),count: this.articleItem.collectionCount,textWidth: $r('app.float.star_icon_width')}).onClick(() => {//5.用户点击收藏图标时,调用处理收藏状态修改的函数this.handleCollected();})}
}
在此方案中,由于文章卡片组件没有绑定AppStorage中key值为“userData”的变量,当用户编辑修改了用户描述userData.description的值时, 文章卡片组件不会重新渲染。
并且,当用户点击文章卡片上的收藏按钮修改文章收藏状态时,变化同步回AppStorage中的key值为“collectedIds”的变量。ArkUI监听到AppStorage中key值为“collectedIds”的值变化,只会通知所有绑定了AppStorage中key值为“collectedIds”变量的组件重新渲染,不会造成“我的“模块用户信息组件“UserInfoView ”重新渲染。
因此,从性能的角度考虑,在使用LocalStorage或AppStorage装饰器存储状态变量时需要合理设计状态的数据结构,避免无意义的渲染刷新。
说明:
过分追求状态结构拆分可能在某些场景导致组件设计过度,不利于维护。此时,可以将对象或类上经常一起改变的几个属性聚合成一个新的对象或类模型,并使用@Observed装饰器修饰,再作为属性挂载到之前的对象或类上。通过此方法,当属性变化时ArkUI只会通知变化给新的对象或类,不会通知最上层的对象。这样既可以有效的减少无用渲染次数,又能使代码更好维护。
如类ClassA上存在属性b、c、d。其中c和d经常一起发生变化,即当c的状态修改时同时也要修改d的状态。
class ClassA{b: string;c: number;d: boolean;
}
此时,将c和d组合在一起做为新的类ClassE的属性并使用@Observed装饰器修饰。对于ClassA去掉c、d属性,新增属性e且其类型为ClassE,设计如下:
class ClassA{b: string;e: ClassE;
}
@Observed
class ClassE{c: number;d: boolean;
}
使用此方案,在AppStorage中存入数据结构为ClassA的变量。当ClassA实例的属性e中的属性c的值变化时,状态变化会通知使用ClassE实例的组件重新渲染,不会通知所有使用AppStorage中ClassA实例的组件更新,即只使用了ClassA实例b属性的组件不会重新渲染。
总结:
上述状态变量案例也可以使用此方法去实现防止资源的浪费,使用@Observed修饰一个新类里面包含collectedIds,当collectedIds发生改变只会刷新新类,而不会刷新UserData,从而避免了资源的浪费。
伪代码如下:
export interface UserData {id: string;username: string;description: string;e: ClassE;@Observed
class ClassE{// 1. 在用户信息UserData上增加用户收藏的资源列表id信息类型定义collectedIds: string[];// ...
}
}
相关文章:

HarmonyOS应用六之应用程序进阶一
目录: 1、UIAbility的冷启动和UIAbility热启动2、静态资源和动态资源的访问3、页面跳转3.1、页面返回跳转 4、HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用4.1、导出HAR的ArkUI组件4.2、引用HAR的ArkUI组件 5、循环渲染6、状态管理最…...
vue开发中变量第一次双向绑定无效,界面并没有变化,第二次则又好了。
这个问题出现的太频繁了,基本大部分用户都遇到这个情况。大部分是弹框的情况。代码如下: <el-dialog:visible.sync="isShowCode" @close="closeCode()"><div class="u4259f"><edite-edite-code isNoShowClose="true"…...
C++基础(8)——string的相关面试题
目录 1.字符串转成整数 2.字符串相加 3.高精度加法模板(acwing) 4.验证回文串 1.字符串转成整数 题目:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。数值为0或者字符串不是一个合法的数值则返回0。输入的…...

【Docker】06-DockerCompose
1. Docker compose 2. Docker Compose部署项目 docker-compose.yml version: "3.8"services:mysql:image: mysqlcontainer_name: mysqlports:- "3307:3306"environment:TZ: Asia/ShanghaiMYSQL_ROOT_PASSWORD: 123volumes:- "/root/docker/mysql/…...

代码随想录训练营Day27 | 77. 组合 | 216.组合总和III | 17.电话号码的字母组合
学习文档:代码随想录 (programmercarl.com) 视频链接:代码随想录算法公开课 | 最强算法公开课 | 代码随想录 (programmercarl.com) Leetcode 77. 组合 题目描述 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以…...

Linux文件重定向文件缓冲区
目录 一、C文件接口 二、系统文件I/O 2.1认识系统文件I/O 2.2系统文件I/O 2.3系统调用和库函数 2.4open( )的返回值--文件描述符 2.5访问文件的本质 三、文件重定向 3.1认识文件重定向 3.2文件重定向的本质 3.3在shell中添加重定向功能 3.4stdout和stderr 3.5如何理…...

训练贪吃蛇ai的后续记录
发现可以结合遗传算法的思路,产生更好的效果。 即每训练一段时间,就停下来测试一下新模型的效果。如果效果优于记录中最好的,则继续导入该模型并训练。重复几次,效果可能更好。 例如,昨晚我便通过唯一一个在十次测试中…...

WPF 手撸插件 八 操作数据库一
1、本文将使用SqlSugar创建Sqlite数据库,进行入门的增删改查等操作。擦,咋写着写着凌乱起来了。 SqlSugar官方文档:简单示例,1分钟入门 - SqlSugar 5x - .NET果糖网 2、环境SqlSugar V5.0版本需要.Net Framework 4.6 ࿰…...

代数结构基础 - 离散数学系列(八)
目录 1. 群(Group) 群的定义 群的示例 2. 环(Ring) 环的定义 环的示例 3. 域(Field) 域的定义 域的示例 域在密码学中的应用 4. 实际应用场景 1. 对称性与加密 2. 误差检测与纠正 3. 数据编码…...
函数的arguments为什么不是数组?如何转化为数组?
因为arguments本身并不能调用数组方法,它是一个另外一种对象类型,只不过属性从0开始排,依次为0 1 2…最后还有callee和length属性,我们也把这样的对象成为类数组。 常见的类数组还有: 1.用getElementsByTagName/Class…...

Java之反射
目录 反射 定义 主要用途 反射相关的类 Class类中【获得类相关方法】 Class类中【获得类中属性相关的方法】 Class类中【获得类中注解相关的方法】 Class类中【获得类中构造器相关的方法】 Class类中【获得类中方法相关的方法】 获得Class对象 代码示例1 代码示例…...

3dsMax添加天空盒
点击渲染,环境 , 点击位图 找到要设置的天空HDR,可以使用HDR(EXR)贴图 一个可以下载HDR贴图的网站 https://polyhaven.com/hdris在渲染的时候不要使用使用微软输入法,3dsmax会卡死, 在渲染的时候不要使用使用微软…...

C语言的类型提升机制
概念 在C语言中,整数类型按照其大小可以分为以下几类(从小到大): charshortintlonglong long 当在表达式中涉及这些类型的混合运算时,较小的类型会被提升为较大的类型。具体规则如下: ①char 和 short …...

Pandas和Seaborn数据可视化
Pandas数据可视化 学习目标 本章内容不需要理解和记忆,重在【查表】! 知道数据可视化的重要性和必要性知道如何使用Matplotlib的常用图表API能够找到Seaborn的绘图API 1 Pandas数据可视化 一图胜千言,人是一个视觉敏感的动物,大…...
爬虫(Python版本)
1.爬虫的法律问题 爬虫技术(Web Scraping)指通过程序自动访问网页并提取其中的数据。在使用爬虫的过程中,涉及到一些法律法规和合规性问题。 常见法律风险 ①未经授权的访问:很多网站对爬虫行为设置了限制。如果未获得授权就进行…...
【分布式训练 debug】VS Code Debug 技巧:launch.json实用参数
VS Code Debug技巧:launch.json实用参数 在使用Visual Studio Code (VS Code)进行调试时,launch.json文件是一个强大的工具,它允许你自定义调试会话。以下是一些实用的参数,可以帮助你更有效地调试Python代码。 1. 调试第三方库…...
pycharm连接linux服务器需要提前安装ssh服务
在 Debian 或 Ubuntu 系统上,使用 APT: bash复制代码 sudo apt-get install openssh-server 在基于 RPM 的系统如 CentOS 或 RHEL 上,使用 YUM 或 DNF: bash复制代码 sudo yum install openssh-server 或对于较新的 RHEL/Cent…...

通信工程学习:什么是LAN局域网、MAN城域网、WAN广域网
LAN局域网、MAN城域网、WAN广域网 LAN(Local Area Network,局域网)、MAN(Metropolitan Area Network,城域网)和WAN(Wide Area Network,广域网)是计算机网络中根据覆盖范围…...
LeetCode热题100速通
一丶哈希 1、两数之和(简单) 给定一个整数数组 n u m s nums nums 和一个整数目标值 t a r g e t target target,请你在该数组中找出 和为目标值 t a r g e t target target 的那 两个 整数,并返回它们的数组下标。 你可以假设…...
Python代码编写KDJ指标
KDJ指标由三部分组成:K值、D值、J值,主要用于分析股票市场的超买超卖状态及股价波动的趋势。博主记录学习编写KDJ指标线 import numpy as npdef calculate_kdj(close_prices, n9, m13, m23):"""计算KDJ指标:param close_prices: 收盘价序…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...