当前位置: 首页 > news >正文

【Harmony】状态管理(V1)

一、概述

文章目录

  • 一、概述
  • 二、组件状态管理
    • 1、@State
      • 1.1、@State简介
      • 1.2、@State简单示例
    • 2、@Prop
      • 2.1、@Prop简介
      • 2.2、@Prop底层实现原理
      • 2.3、@Prop简单示例
    • 3、@Link
      • 3.1、@Link简介
      • 3.2、@Link底层实现原理
      • 3.3、@Link简单示例
    • 4、@Provide @Consume
      • 4.1、@Provide @Consume简介
      • 4.2、@Provide @Consume底层实现原理
      • 4.3、常见应用场景
    • 5、@Observed @ObjectLink
      • 5.1、@Observed @ObjectLink简介
      • 5.2、@Observed @ObjectLink底层实现原理
  • 三、应用状态管理
    • 1、LocalStorage
      • 1.1、LocalStorage简介
      • 1.2、LocalStorage相关原理
      • 1.3、LocalStorage简单示例
    • 2、AppStorage
      • 2.1、AppStorage简介
      • 2.2、AppStorage相关原理
      • 2.3、AppStorage简单示例
    • 3、PersistentStorage
      • 3.1、PersistentStorage简介
      • 3.2、PersistentStorage相关原理
      • 3.3、PersistentStorage简单示例
    • 4、Environment
      • 4.1、Environment简介
      • 4.2、Environment简单示例
  • 四、其他状态管理
    • 1、@Watch
      • 1.1、@Watch简介
      • 1.2、@Watch相关原理
      • 1.3、@Watch简单示例
    • 2、$$语法
    • 3、@Track
      • 3.1、@Track简介
      • 3.2、@Track相关原理
      • 3.3、@Track简单示例
    • 4、自定义组件冻结功能
  • 五、面试题回答模板(待完善)
    • 1、简述@Link实现原理
    • 2、简述@Prop实现原理
    • 3、简述@Prop和@Link的区别
    • 4、简述@Provide @Consume和@Link的区别

组件状态管理:@State@Prop@Link@Provide @Consume@Observed @ObjectLink 受限 对象、数组
应用状态管理:LocalStorageAppStoragePersistentStorage@StorageProp @StorageLink

官方文档地址:状态管理(V1)

二、组件状态管理

1、@State

1.1、@State简介

@State装饰的变量为状态变量,在组件内进行状态管理。一旦拥有了状态属性,就会和组件的渲染绑定起来,当状态变化的时候,会调用当前绑定状态变量的组件的build方法刷新UI

使用@State要注意:

1、@State只能在组件内访问
2、支持多种变量的类型
3、需要初始化
4、组件不同实例,数据独立

修饰数组或者对象的时候,可以驱动UI更新,但是,只能更新一层,不能做深层渲染

1.2、@State简单示例

/*** 装饰器@State 详解*/
@Entry
@Component
struct Demo01Page {//修饰基本类型的变量//修饰变量的时候要赋值@State name:string ="孙悟空"@State age:number =19//修饰对象@State emp:Emp = {id:1,name:"喜洋洋",age:2,car:{carId:666,carBrand:"法拉利"}}//修饰普通类型的数组// @State arr:string[] = ["lucy",'lily',"david"]@State arr:Array<string> = ["lucy",'lily',"david"]//修饰的事汽车数组@State carList:Car[] = [{carId:1,carBrand:"法拉利"},{carId:2,carBrand:"劳斯莱斯幻影"},{carId:3,carBrand:"宝马"},{carId:4,carBrand:"奔驰"},]build() {Column({space:5}){Text("基本类型的变量")Text(this.name).fontSize(25).onClick(()=>{this.name = "猪八戒"console.log(this.name)})//如果name没有state,也会在某些情况发生渲染//age发生了变化,age发生了变化就会通知Text组件的build刷新UI//name跟着沾光Text(this.name+this.age+"").onClick(()=>{this.age++})Divider()Text("修饰对象class interface")Text(JSON.stringify(this.emp)).onClick(()=>{//没有car的情况一,更新本身// this.emp = {id:2,name:"灰太狼",age:18}//没有car情况二:更新对象的属性(一级属性)//this.emp.name="灰太狼"//有car 更新emp 更新本身// this.emp = {id:3,name:"tom",age:18,car:{carId:111,carBrand:"劳斯莱斯"}}//更新对象的一级属性(对象的直接属性)//this.emp.car = {carId:333,carBrand:"宝马"}//员工的汽车属于一级属性//员工的汽车的属性属于二级属性,嵌套属性,嵌套属性的变化不会产生渲染this.emp.car.carBrand ="奥迪"})Divider()Text("修饰普通类型的数组")Text(JSON.stringify(this.arr)).onClick(()=>{//数组一级属性指的是下标对应的值//本身是会引起渲染的// this.arr = ['a','b','c']//一级属性也会引起渲染// this.arr[0]='张三'// this.arr.push("zhang")this.arr.splice(0,1)})Divider()Text("修饰的对象数组")Text(JSON.stringify(this.carList)).onClick(()=>{//直接改变数组本身没有问题// this.carList =[]//修改数组的一级属性,也会发生变化// this.carList[3] = {carId:5,carBrand:"奥迪"}//修改数组中的某个对象的属性 属于深层嵌套,不会发生渲染this.carList[3].carBrand="奥迪"})}}
}//声明一个类的时候,属性必须赋值,否则报错
/*class Emp{id:numbername:stringage:number
}*/
//解决方案一 属性可选
// class Emp{
//   id?:number
//   name?:string
//   age?:number
// }
// let emp:Emp = {id:10,name:"",age:30}
// let emp2:Emp = new Emp()
// emp2.id =10;
// emp2.name=""
// emp2.age =19
//解决方案二 给赋值
// class Emp{
//   id:number = -1
//   name:string =""
//   age:number = -1
// }
// let emp:Emp = {id:10,name:"",age:30}
// let emp2:Emp = new Emp()
// emp2.id =10;
// emp2.name=""
// emp2.age =19
//方案三使用构造函数
// class Emp{
//   id:number
//   name:string
//   age:number
//   constructor(id:number,name:string,age:number) {
//     this.id =id
//     this.name=name
//     this.age =age
//   }
// }
// let emp =new Emp(1,"z行三",19)interface Car{carId:numbercarBrand:string
}interface Emp{id:numbername:stringage:number//员工拥有一辆汽车car:Car
}
// let emp:Emp = {id:-1,name:"zhangsan",age:18}//修饰普通类型属性,值变化直接引起渲染
//修饰对象的时候,对象本身,以及对象属性的变化都会引起渲染
//修改对象A,并且对象A里面还有对象B的时候,
//       修改对象A本身,以及对象A的属性会引起渲染
//       修改对象A 中的对象B的属性的时候属于深层渲染不会引起渲染// 修改数组的时候,更改数值本身,或者下标对应的内容会引起渲染
// 但是修改数组中对象的属性的时候不会引起渲染

2、@Prop

2.1、@Prop简介

@Prop 装饰的变量和父组件建立单向的同步关系:

@Prop 变量允许在本地修改,但修改后的变化不会同步回父组件。

当父组件中的数据源更改时,与之相关的 @Prop 装饰的变量都会自动更新。

2.2、@Prop底层实现原理

​ 简单来说就是当父组件给子组件的**@Prop变量传数据时,ArkUI框架会自动触发深拷贝**。深拷贝后的新实例会覆盖掉子组件原来的旧实例,实现一次单向传递。如果子组件的数据发生变化,修改的是深拷贝后的实例,和父组件的源数据没有关系,所以子组件刷新而父组件不刷新。

补充:

1、深拷贝会递归遍历对象的所有层级属性,逐一复制基本类型的值,遇到引用类型(对象、数组、map、set等)不进行引用传递,而是会new出新的实例,然后再将旧实例里的属性进行复制,和之前一样遇到引用类型就new新的实例然后复制属性,递归重复这个操作直到深拷贝结束。

2、在深拷贝时,基本类型数据是值传递,引用类型没有传递地址,而是new出新实例打破引用链。这样就实现了父组件数据源和子组件数据在内存中完全分离,符合数据单向流动的需求。

2.3、@Prop简单示例

import { webview } from '@kit.ArkWeb'@Entry
@Component
struct Demo02Prop {//父组件有用State状态变量@State emp:Emp = {id:1,name:"开心",age:18,car:{carId:11,carBrand:"法拉利"}}build() {Column(){Text("父组件").fontSize(20)Text(JSON.stringify(this.emp)).onClick(()=>{//直接修改一级属性// this.emp.name="开心果"//修改二级属性父组件都不会产生渲染,子组件自然也就不会产生渲染this.emp.car.carBrand = "大众"})Divider()//使用子组件将值传递时候,父组件的值会自动覆盖子组件的值Zi({ziemp:this.emp})}}
}
@Component
struct Zi {//子组件已经使用@Prop修饰了,所以可以不用赋值@Propziemp:Empbuild() {Row() {Column() {Text("子组件").fontSize(20)Text(JSON.stringify(this.ziemp)).onClick(()=>{//子组件如果发生了渲染不会通知到父组件//换句话 子组件发生了渲染,父组件也不会发生渲染// this.ziemp.name="Kaixin"this.ziemp.car.carId=10})}.width("100%").height("100%")}.width("100%").height("100%")}
}
interface Car{carId:numbercarBrand:string
}
interface Emp{id:numbername:stringage:number//员工拥有一辆汽车car:Car
}

3、@Link

3.1、@Link简介

​ 父子双向同步@Link,子组件中被 @Link 装饰的变量与其父组件中对应的数据源建立双向数据绑定。父组件数据变化引起渲染,那么子组件跟着渲染,反之子组件数据变化引起渲染,那么父组件也跟着渲染。

注意:

@Link 装饰器不能在 @Entry 装饰的自定义组件中使用。

3.2、@Link底层实现原理

​ 简单来说@Link的核心是直接绑定父组件的原始数据引用,而非拷贝数据。当父组件将数据传递给子组件的@Link变量时,实际传递的是数据的内存地址引用。父子组件操作的是同一块内存数据,任何一方的修改都会实时同步到另一方。

扩展:
1、依赖收集:ArkUI框架在初始化时,会为每个@Link变量创建依赖关系图,记录哪些子组件的@Link绑定了父组件的具体数据。

2、变更通知”:当父组件数据变化(如通过@State修饰的变量更新),框架通过发布-订阅模式通知所有关联的@Link变量,触发子组件重新渲染。

3、数据劫持与响应式触发:父组件的数据(如@State变量)会被框架用Proxy或Object.defineProperty包装,拦截getset操作。当子组件通过@Link读取数据时,触发get,自动建立父子组件的依赖关系。当子组件修改@Link数据时,触发set,直接修改父组件数据源,并通知所有关联组件更新。

3.3、@Link简单示例

import { webview } from '@kit.ArkWeb'@Entry
@Component
struct Demo03Link {//父组件有用State状态变量@State emp:Emp = {id:1,name:"开心",age:18,car:{carId:11,carBrand:"法拉利"}}build() {Column(){Text("父组件").fontSize(20)Text(JSON.stringify(this.emp)).onClick(()=>{//直接修改一级属性this.emp.name="开心果"//修改二级属性父组件都不会产生渲染,子组件自然也就不会产生渲染// this.emp.car.carBrand = "大众"})Divider()//使用子组件将值传递时候,父组件的值会自动覆盖子组件的值Zi({ziemp:this.emp})}}
}/****/
@Component
struct Zi {//子组件已经使用@Link修饰了,所以可以不用赋值@Linkziemp:Empbuild() {Row() {Column() {Text("子组件").fontSize(20)Text(JSON.stringify(this.ziemp)).onClick(()=>{//子组件如果发生了渲染会通知到父组件//换句话 子组件发生渲染,父组件也会发生渲染// this.ziemp.name="Kaixin"//子组件如果数据变化了,子组件不产生渲染,父组件也不会产生渲染this.ziemp.car.carId=10})}.width("100%").height("100%")}.width("100%").height("100%")}
}interface Car{carId:numbercarBrand:string
}interface Emp{id:numbername:stringage:number//员工拥有一辆汽车car:Car
}
// build函数里面书写的内容要注意什么规范?
//1、只能有一个根组件
//2、不能定义变量
//3、不能直接console.log
//4、不能直接调用普通函数,如果要调用普通函数有返回值可以在组件或者是属性中调用
//5、不能写switch
//6、如果要调用函数,函数得用@Builder进行修饰/*** 函数的按值传递*/
// let a  =2
// let b = 3
// function fun1(a:number,b:number){
//   a=a+a
//   b=b+b
// }
// fun1(a,b)
// console.log("值是:",a,b)/*
按值赋值*/
/*let a =2
let b= a
a =100
console.log("b",b)*///数值 布尔 字符串 都是按值传递
//对象、数组 按引用/*函数的按引用传递*/
/*
let arr:number[] = [2,3]function  fun2(arr:number[]){arr[0]= arr[0]+arr[0]arr[1] = arr[1]+arr[1]
}
fun2(arr)
console.log("数组中的值:",arr[0],arr[1])
*//*变量按引用赋值*/
let arr1:number[]=[2,3]
let arr2:number[]=arr1
arr1[0] =10
console.log(JSON.stringify(arr2))

4、@Provide @Consume

4.1、@Provide @Consume简介

@Provide @Consume组合使用可以跨层级双向同步和绑定,而无需通过调用组件传参实现传递绑定。

  • @Provide 在祖先组件中定义数据源,允许所有后代组件直接访问。
  • @Consume 在后代组件中消费数据,修改数据时会同步到所有关联组件。
  • 数据更新时,任意一方的修改都会触发全链路的响应式同步。

4.2、@Provide @Consume底层实现原理

  1. 引用传递与共享内存
    • 无深拷贝机制:与 @Prop 不同,@Provide@Consume 直接传递数据的内存引用,父子组件共享同一份数据实例。
    • 上下文注入:框架通过隐式的上下文对象(Context)管理数据引用,使后代组件能直接访问祖先的数据源。
  2. 依赖追踪与更新传播
    • 订阅机制:当组件通过 @Consume 声明依赖时,框架自动建立数据与组件的订阅关系
    • 变更广播:数据发生修改时,框架通过依赖树精准通知所有关联组件,触发局部刷新。
  3. 双向同步流程
    • 祖先修改@Provide 数据更新时,通过引用直接同步到所有 @Consume 组件。
    • 后代修改@Consume 组件修改数据时,直接修改共享内存的实例,触发祖先和同级消费者的同步更新。

4.3、常见应用场景

  • 全局主题配置:祖先组件提供主题色,后代组件直接消费并实时响应变化。
  • 跨层级表单控制:表单根组件管理数据,深层嵌套的表单项直接修改数据源。
  • 状态共享中间件:替代 Redux 等状态管理库,简化组件间共享状态的逻辑。

5、@Observed @ObjectLink

限制条件巨多,能不使用就不使用,或者直接使用@ObservedV2版本

5.1、@Observed @ObjectLink简介

嵌套对象属性级同步,@Observed@ObjectLink 用于实现嵌套对象属性的响应式更新,解决复杂对象(对象数组,嵌套对象等)的局部数据变更同步问题。

  • @Observed:装饰类,标记该类为可观察对象,其属性变化可被框架追踪。
  • @ObjectLink:装饰变量,用于接收被观察对象的引用,支持对嵌套属性的直接修改和同步。
  • 父子组件间通过共享对象引用,实现对象属性变化的双向同步。

限制条件:

1.使用new创建被@Observed装饰的类,才可以被观察到属性的变化。

2.@ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用@Prop。

​ 2.1@Prop装饰的变量和数据源的关系是是单向同步,@Prop装饰的变量在本地拷贝了数据源,所以它允许本地更改,如果父组件中的数据源有更新,@Prop装饰的变量本地的修改将被覆盖。

​ 2.2@ObjectLink装饰的变量和数据源的关系是双向同步,@ObjectLink装饰的变量相当于指向数据源的指针。禁止对@ObjectLink装饰的变量赋值,如果一旦发生@ObjectLink装饰的变量的赋值,则同步链将被打断。因为@ObjectLink装饰的变量通过数据源 (Object)引用来初始化。对于实现双向数据同步的@ObjectLink,赋值相当于更新父组件中的数组项或者class的属性, TypeScript/JavaScript不能实现,会发生运行时报错。

3.@Observed装饰的类,如果其属性为非简单类型,比如class、Object或者数组,也需要被@Observed装饰,否则将观察不到其属性的变化。

4.使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。

5.@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。只能在子组件中使用

5.2、@Observed @ObjectLink底层实现原理

  1. 可观察类包装
    • @Observed 的作用:框架会为被装饰的类生成代理,拦截属性的 getter/setter 方法,自动追踪属性读写操作。
    • 依赖收集:当组件通过 @ObjectLink 访问对象属性时,框架记录属性与组件的依赖关系。
  2. 引用传递与属性监听
    • 属性级更新:仅当被监听的具体属性发生变更时,触发关联组件的精准更新(非全对象刷新)。
  3. 双向同步机制
    • 子组件修改属性:通过 @ObjectLink 直接修改对象属性,触发父组件和同级组件的同步更新。
    • 父组件修改属性:若父组件修改被观察对象的属性,所有持有该对象引用的 @ObjectLink 变量自动更新。

三、应用状态管理

1、LocalStorage

1.1、LocalStorage简介

页面级状态共享,用于同一页面多个组件间的数据同步(非跨页面),也就是1个父组件和N个子组件之间的同步。(通过GetShared接口实现跨页面共享)

补充:大多数情况都是同一页面使用,但是它也支持多页面使用:

1.将LocalStorage实例从UIAbility共享到一个或多个视图:在uiAbility生命周期中注入实例官方示例

2.除了根节点可通过@Entry来接收LocalStorage实例,自定义组件(子节点)也可以通过构造参数来传递LocalStorage实例:子组件被调用时也可通过构造参数来传递官方示例

let ls = new LocalStorage({ 'fontSize': 16 });  // 必须指定初始值
@Entry(ls)  // 根组件必须通过@Entry绑定

关键限制:

  • 属性值类型不可动态变更(初始化后禁止修改类型)
  • 不同UIAbility间的LocalStorage实例相互隔离

1.2、LocalStorage相关原理

  1. 存储机制:数据存储在页面内存中,生命周期与页面绑定(页面销毁时释放)。
  2. 同步机制
    • 单向同步@LocalStorageProp装饰的变量仅从LocalStorage接收更新,本地修改不反馈回LocalStorage。
    • 双向同步@LocalStorageLink装饰的变量与LocalStorage双向绑定,修改会同步到LocalStorage及其他绑定组件。
  3. 实例管理
    • 根组件通过@Entry绑定LocalStorage实例,子组件继承访问。
    • 每个页面可创建多个实例,但组件树仅能访问一个实例。

1.3、LocalStorage简单示例

import { User } from '../../model/Person'
import { UserInfo } from '../../model/User'//1.准备数据
let parms:Record<number,number> ={"123":123456}
let user:UserInfo = {name:"lisi",age:123}
//2.实例化LocalStorage,他有构造函数可以在实例化时初始话参数
let local:LocalStorage=new LocalStorage(parms)//3.setOrCreate可以追加和修改参数,但key值存在时就修改,当key不存在时就创建
local.setOrCreate("123",123)
local.setOrCreate("user",user)//4.将LocalStorage传入@Entry的括号中,LocalStorage只能通过父组件传入,其后代都可以使用,
// 通过@LocalStorageLink("key")双向和@LocalStorageProp("key")单向同步数据
@Entry(local)
@Component
struct Page_01_LocalStarge {//LocalStorageLink("key") 如果key存在于LocalStorage就使用存储的值替换这里的本地初始化的值,//如果key不存在于LocalStorage,那么就会用这个key在LocalStorage创建一条新的记录,并且值为本地初始化的值@LocalStorageLink("user")user:UserInfo = {} as User;@LocalStorageLink("123")num:number = 0;build() {Column(){Text(JSON.stringify(this.user)).onClick(()=>{this.user.name="wangwu"})Text(this.num+"").onClick(()=>{this.num++})Divider()LocalStorage_01()LocalStorage_01()}.height('100%').width('100%')}
}@Component
struct LocalStorage_01{@LocalStorageLink("user")user_localstorage:UserInfo = {} as User;@LocalStorageLink("123")num_num:number = 0;build() {Column(){Text(JSON.stringify(this.user_localstorage)).onClick(()=>{this.user_localstorage.name="zhaoliu"})Text(this.num_num+"").onClick(()=>{this.num_num++})}}
}

2、AppStorage

2.1、AppStorage简介

​ 应用级全局单例存储,支持跨页面、跨UIAbility数据共享,数据生命周期与应用进程一致

AppStorage.setOrCreate('user', { name: 'John' });  // 动态创建属性
AppStorage.delete('tempData');  // 手动删除属性

2.2、AppStorage相关原理

  1. 存储机制:数据存储在应用内存中,应用退出时销毁(非持久化)。
  2. 同步机制
    • 单向同步@StorageProp仅接收AppStorage更新,本地修改不反馈。
    • 双向同步@StorageLink实现双向同步,修改会触发全局UI更新。
  3. 协作机制
    • 可与LocalStorage通过LocalStorage.getShared()选择性同步数据。
    • 与PersistentStorage协作时,AppStorage中的值会覆盖PersistentStorage同名属性。
  4. 全局共享原理
    1. 数据覆盖规则
      • 应用启动时:PersistentStorage的数据会覆盖AppStorage同名属性
      • 运行时:AppStorage的修改会覆盖PersistentStorage的值
    2. 环境变量联动
      • 通过 Environment.EnvProp 将设备环境变量(如语言/区域)自动同步到AppStorage
      • 使用 @StorageProp('language') 可直接读取环境参数

2.3、AppStorage简单示例

从UI内部使用:官方示例

从应用逻辑使用:官方示例

3、PersistentStorage

3.1、PersistentStorage简介

​ 持久化存储AppStorage中的指定属性,应用重启后保留数据(如用户配置)。

// 正确示例:未在AppStorage预定义属性
PersistentStorage.persistProp('num', 123);  // 报错:'theme'未定义// 错误流程1.AppStorage在PersistentStorage之前定义
AppStorage.setOrCreate('num', 987);  //每次应用重启,AppStorage的值(987)会覆盖PersistentStorage里的值(123)
PersistentStorage.persistProp('num',123);// 错误流程2.AppStorage在PersistentStorage之后定义
PersistentStorage.persistProp('num',123); //每次应用重启,AppStorage的值(987)会覆盖PersistentStorage里的值(123)
AppStorage.setOrCreate('num', 987);  //正确流程2.AppStorage在PersistentStorage之后定义,通过判断来决定是否覆盖
PersistentStorage.persistProp('num',123); //先定义
if(AppStorage.get('num'>130)){//通过判断决定是否覆盖AppStorage.setOrCreate('num', 987); 
}

3.2、PersistentStorage相关原理

1.存储机制

  • 数据异步写入本地磁盘,避免阻塞UI。
  • 仅支持基础类型(string、number、boolean等),复杂数据需序列化。
  • 数据变更后延迟300ms异步写入磁盘(防频繁IO操作)
  • 应用退出时强制执行未完成的写入操作

2.绑定规则

  • 通过PersistentStorage.PersistProp()绑定AppStorage中的属性键值。
  • 初始化时优先读取磁盘数据,若AppStorage已存在同名属性,则覆盖磁盘值。

3.限制条件

  • 必须在AppStorage中先定义属性,再调用PersistProp()
  • 异步写入可能导致数据更新延迟,需注意一致性处理。

3.3、PersistentStorage简单示例

PersistentStorage文档地址:官方示例

4、Environment

4.1、Environment简介

​ 开发者如果需要应用程序运行的设备的环境参数,以此来作出不同的场景判断,比如多语言,深浅色模式等,需要用到Environment设备环境查询。

​ Environment是ArkUI框架在应用程序启动时创建的单例对象。它为AppStorage提供了一系列描述应用程序运行状态的属性。Environment的所有属性都是不可变的(即应用不可写入),所有的属性都是简单类型。

​ Environment提供了读取系统某些环境变量的能力,具体见Environment内置参数,并将其值写入AppStorage里,所以开发者需要通过AppStorage才能获取环境变量的值。

Environment内置参数:

数据类型描述
accessibilityEnabledboolean获取无障碍屏幕读取是否启用。
colorModeColorMode色彩模型类型:选项为ColorMode.LIGHT: 浅色,ColorMode.DARK: 深色。
fontScalenumber字体大小比例。开发者需要配置configuration使fontScale跟随系统变化。
fontWeightScalenumber字体粗细程度。
layoutDirectionLayoutDirection布局方向类型:包括LayoutDirection.LTR: 从左到右,LayoutDirection.RTL: 从右到左。
languageCodestring当前系统语言值,取值必须为小写字母, 例如zh。

4.2、Environment简单示例

文档地址:官方示例

四、其他状态管理

1、@Watch

1.1、@Watch简介

​ @Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用。@Watch在ArkUI框架内部判断数值有无更新使用的是严格相等(===),遵循严格相等规范。当严格相等判断的结果是false(即不相等)的情况下,就会触发@Watch的回调。

装饰器说明

@Watch补充变量装饰器说明
装饰器参数必填。常量字符串,字符串需要有引号。是自定义成员函数的方法的引用
可装饰的自定义组件变量可监听所有装饰器装饰的状态变量。不允许监听常规变量。
装饰器的顺序装饰器顺序不影响实际功能,开发者可以根据自己的需要决定装饰器顺序的先后。建议@State、@Prop、@Link等装饰器在@Watch装饰器之前,以保持整体风格的一致。
@Watch触发时机使用@Watch来监听状态变量变化时,回调触发时间是变量真正变化、被赋值的时间。详细示例请参考使用场景中的@Watch的触发时机。

1.2、@Watch相关原理

观察变化和行为表现

  1. 当观察到状态变量的变化(包括双向绑定的AppStorage和LocalStorage中对应的key发生的变化)的时候,对应的@Watch的回调方法将被触发;
  2. @Watch方法在自定义组件的属性变更之后同步执行;
  3. 如果在@Watch的方法里改变了其他的状态变量,也会引起状态变更和@Watch的执行;
  4. 在第一次初始化的时候,@Watch装饰的方法不会被调用,即认为初始化不是状态变量的改变。只有在后续状态改变时,才会调用@Watch回调方法。

限制条件:

  • 建议开发者避免无限循环。循环可能是因为在@Watch的回调方法里直接或者间接地修改了同一个状态变量引起的。为了避免循环的产生,建议不要在@Watch的回调方法里修改当前装饰的状态变量;
  • 开发者应关注性能,属性值更新函数会延迟组件的重新渲染(具体请见上面的行为表现),因此,回调函数应仅执行快速运算;
  • 不建议在@Watch函数中调用async await,因为@Watch设计的用途是为了快速的计算,异步行为可能会导致重新渲染速度的性能问题。

1.3、@Watch简单示例

@Component
struct TotalView {@Prop @Watch('onCountUpdated') count: number = 0;@State total: number = 0;// @Watch 回调onCountUpdated(propName: string): void {this.total += this.count;}build() {Text(`Total: ${this.total}`)}
}@Entry
@Component
struct CountModifier {@State count: number = 0;build() {Column() {Button('add to basket').onClick(() => {this.count++})TotalView({ count: this.count })}}
}

2、$$语法

​ $$运算符为系统内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步。内部状态具体指什么取决于组件。例如,TextInput组件的text参数。

补充:

$$还用于@Builder装饰器的按引用传递参数,开发者需要注意两种用法的区别。

使用规则:

  • 当前$$支持基础类型变量,以及@State、@Link和@Prop装饰的变量。

  • 当前$$支持的组件:

    组件支持的参数/属性起始API版本
    Checkboxselect10
    CheckboxGroupselectAll10
    DatePickerselected10
    TimePickerselected10
    MenuItemselected10
    Panelmode10
    Radiochecked10
    Ratingrating10
    Searchvalue10
    SideBarContainershowSideBar10
    Slidervalue10
    Stepperindex10
    Swiperindex10
    Tabsindex10
    TextAreatext10
    TextInputtext10
    TextPickerselected、value10
    ToggleisOn10
    AlphabetIndexerselected10
    Selectselected、value10
    BindSheetisShow10
    BindContentCoverisShow10
    Refreshrefreshing8
    GridItemselected10
    ListItemselected10
  • $$绑定的变量变化时,会触发UI的同步刷新。

3、@Track

3.1、@Track简介

​ @Track应用于class对象的属性级更新。@Track装饰的属性变化时,只会触发该属性关联的UI更新。

​ @Track是class对象的属性装饰器。当一个class对象是状态变量时,@Track装饰的属性发生变化,只会触发该属性关联的UI更新;如果class类中使用了@Track装饰器,则未被@Track装饰器装饰的属性不能在UI中使用,如果使用,会发生运行时报错。

3.2、@Track相关原理

3.3、@Track简单示例

使用@Track装饰器可以避免冗余刷新。

class LogTrack {@Track str1: string;@Track str2: string;constructor(str1: string) {this.str1 = str1;this.str2 = 'World';}
}class LogNotTrack {str1: string;str2: string;constructor(str1: string) {this.str1 = str1;this.str2 = '世界';}
}@Entry
@Component
struct AddLog {@State logTrack: LogTrack = new LogTrack('Hello');@State logNotTrack: LogNotTrack = new LogNotTrack('你好');isRender(index: number) {console.log(`Text ${index} is rendered`);return 50;}build() {Row() {Column() {Text(this.logTrack.str1) // Text1.fontSize(this.isRender(1)).fontWeight(FontWeight.Bold)Text(this.logTrack.str2) // Text2.fontSize(this.isRender(2)).fontWeight(FontWeight.Bold)Button('change logTrack.str1').onClick(() => {this.logTrack.str1 = 'Bye';})Text(this.logNotTrack.str1) // Text3.fontSize(this.isRender(3)).fontWeight(FontWeight.Bold)Text(this.logNotTrack.str2) // Text4.fontSize(this.isRender(4)).fontWeight(FontWeight.Bold)Button('change logNotTrack.str1').onClick(() => {this.logNotTrack.str1 = '再见';})}.width('100%')}.height('100%')}
}

在上面的示例中:

  1. 类LogTrack中的属性均被@Track装饰器装饰,点击按钮"change logTrack.str1",此时Text1刷新,Text2不刷新,只有一条日志输出,避免了冗余刷新。

    Text 1 is rendered
    
  2. 类logNotTrack中的属性均未被@Track装饰器装饰,点击按钮"change logNotTrack.str1",此时Text3、Text4均会刷新,有两条日志输出,存在冗余刷新。

    Text 3 is renderedText 4 is rendered
    

4、自定义组件冻结功能

​ 内容颇多,这里只做介绍,详情自行查看,文档地址:自定义组件冻结功能的官方文档

​ 自定义组件冻结功能专为优化复杂UI页面的性能而设计,尤其适用于包含多个页面栈、长列表或宫格布局的场景。在这些情况下,当状态变量绑定了多个UI组件,其变化可能触发大量UI组件的刷新,进而导致界面卡顿和响应延迟。为了提升这类负载UI界面的刷新性能,开发者可以选择尝试使用自定义组件冻结功能。

组件冻结的工作原理是:

  1. 开发者通过设置freezeWhenInactive属性,即可激活组件冻结机制。
  2. 启用后,系统将仅对处于激活状态的自定义组件进行更新,这使得UI框架可以尽量缩小更新范围,仅限于用户可见范围内(激活状态)的自定义组件,从而提高复杂UI场景下的刷新效率。
  3. 当之前处于inactive状态的自定义组件重新变为active状态时,状态管理框架会对其执行必要的刷新操作,确保UI的正确展示。

​ 简而言之,组件冻结旨在优化复杂界面下的UI刷新性能。在存在多个不可见自定义组件的情况下,如多页面栈、长列表或宫格,通过组件冻结可以实现按需刷新,即仅刷新当前可见的自定义组件,而将不可见自定义组件的刷新延迟至它们变为可见时。

​ 需要注意,组件active/inactive并不等同于其可见性。组件冻结目前仅适用于以下场景:

  1. 页面路由:当前栈顶页面为active状态,非栈顶不可见页面为inactive状态。

  2. TabContent:只有当前显示的TabContent中的自定义组件处于active状态,其余则为inactive。

  3. LazyForEach:仅当前显示的LazyForEach中的自定义组件为active状态,而缓存节点的组件则为inactive状态。

  4. Navigation:当前显示的NavDestination中的自定义组件为active状态,而其他未显示的NavDestination组件则为inactive状态。

  5. 组件复用:进入复用池的组件为inactive状态,从复用池上树的节点为active状态。

    其他场景,如堆叠布局(Stack)下的被遮罩的组件,这些组件尽管不可见,但并不被视为inactive状态,因此不在组件冻结的适用范围内。

五、面试题回答模板(待完善)

1、简述@Link实现原理

@Link的底层实现可以分为三个方面理解:

  1. 引用传递:父组件把数据的‘内存地址’直接传给子组件,双方操作同一份数据。
  2. 响应式监听:框架通过Proxy监控数据变化,无论父子哪边修改,都能立刻触发对方更新。
  3. 依赖管理:每个@Link变量背后都有一个依赖列表,数据变化时精准通知相关组件,避免无效渲染。

​ 这就像父子组件共用一张草稿纸,任何一方写字,另一方都能实时看到。

2、简述@Prop实现原理

@Link的底层实现可以分为两个方面理解:

1. 核心机制:深拷贝
“@Prop的核心是深拷贝隔离。当父组件给子组件的@Prop传数据时,框架会像‘复印机’一样,递归复制所有层级的数据,生成一个完全独立的新对象。

  • 基本类型:直接复制值(比如数字、字符串)。
  • 引用类型:遇到对象、数组,会先new一个空壳,再把里面的值一层层扒开复制,彻底斩断和原数据的关联。
    最终子组件拿到的是一个‘只读副本’,和父组件数据在内存里完全隔离。

2. 更新触发规则
@Prop的数据流动是单向的,只有父改子,子不能反向改父:

  • 父组件更新:父数据变化时,会触发新一轮深拷贝,生成新副本覆盖子组件的旧数据,导致父子组件一起刷新。
  • 子组件修改:子组件可以改自己的@Prop副本,但改的是‘复印件’,父组件的‘原件’完全不受影响,所以只有子组件自己会刷新。

3、简述@Prop和@Link的区别

@Prop和@Link的区别主要体现在数据传递方式上:

  1. 数据隔离性:@Prop会深拷贝父数据,生成独立副本,子组件修改不影响父组件;@Link直接绑定父数据的引用,双方共享同一份数据。
  2. 同步方向:@Prop是单向同步,只能父传子;@Link是双向同步,父子互相实时同步。
  3. 适用场景:@Prop适合需要数据隔离的静态展示组件,比如商品卡片;@Link适合需要双向交互的控件,比如表单输入框。

4、简述@Provide @Consume和@Link的区别

​ @Provide/@Consume 和 @Link 都用于实现双向数据同步,但设计目标不同。@Link 专注直接父子组件的高效通信,通过显式参数传递共享内存引用,适合简单层级的高性能场景;@Provide/@Consume 则通过上下文机制实现跨层级数据穿透,省去中间组件的传递成本,但需要维护更复杂的依赖关系,适合深层组件共享低频数据的场景。二者在性能与便利性之间做了权衡,因此需要根据组件层级和数据使用范围选择合适的方案。

可补充说明:

  • 在 ArkUI 的响应式系统中,优先使用 @Link 保持数据流透明性
  • 对全局状态(如 Redux 管理的状态),可用 @Provide/@Consume 替代部分状态管理库的功能
  • 超深层级(5层以上)优先考虑 @Provide/@Consume,但需警惕过度使用导致的维护成本

相关文章:

【Harmony】状态管理(V1)

一、概述 文章目录 一、概述二、组件状态管理1、State1.1、State简介1.2、State简单示例 2、Prop2.1、Prop简介2.2、Prop底层实现原理2.3、Prop简单示例 3、Link3.1、Link简介3.2、Link底层实现原理3.3、Link简单示例 4、Provide Consume4.1、Provide Consume简介4.2、Provide …...

udev规则实例:监听usb插拔事件并做出相应

在 Linux 和 Android 系统中&#xff0c;USB 插拔事件的判断涉及从内核到用户空间的多层协作。以下是源码中关键判断点的梳理&#xff1a; 事件流程 内核层&#xff1a;UEvent 机制 USB 插拔事件首先由内核通过 UEvent 机制 上报。内核中的 USB 驱动&#xff08;如 drivers/…...

【算法】【蓝桥23国A软件C】四版代码思路分析与逐步优化

题目来源&#xff1a;第十四届蓝桥杯大赛软件赛国赛C/C 大学 A 组 题目描述&#xff1a; 问题描述 给定一个 WH 的长方形&#xff0c;两边长度均为整数。小蓝想把它切割为很多个边长为整数的小正方形。假设切割没有任何损耗&#xff0c;正方形的边长至少为 2&#xff0c;不允…...

程序设计竞赛1

题目1 2025年春节期间&#xff0c;DeepSeek作为“AI界的天降紫微星”成为新晋效率神器&#xff0c;热度席卷全球&#xff0c;其团队主创成员也迅速引起了大家的关注。 DeepSeek之所以能在短时间内取得如此不凡成绩&#xff0c;与其团队成员的背景密不可分。团队汇聚了来自清华…...

android studio 2022打开了v1 签名但是生成的apk没有v1签名问题

我使用了Android Studio Flamingo | 2022.2.1 Patch 2版本的IDE编译了一个apk,但是apksigner查看apk的签名信息时,发现只有v2签名,没有v1签名。 apksigner verify -v app-debug.apk ​​​​​​​Verifies Verified using v1 scheme (JAR signing): false Verified usin…...

EPGAN:融合高效注意力的生成对抗网络图像修复算法

简介 简介:利用掩码设计来遮掉输入图像的一部分,将这类图像输入给生成器。生成器结合ECA注意力机制架构,利用感知损失、对抗损失和均方误差损失的加权和来作为生成器的损失计算。鉴别器分别对应掩码和整张图做损失计算。 论文题目:融合高效注意力的生成对抗网络图像修复算…...

使用模板报错:_G.unicode.len(orgline.text_stripped:gsub(“ “,““))

使用aegisub制作歌词特效&#xff0c;白嫖大佬的自动化模板时&#xff0c;经常会遇到如下报错&#xff1a; Runtime error in template code: Expected 1 arguments, got 2 Code producing error: ci {0,0}; cn _G.unicode.len(orgline.text_stripped:gsub(" ",&q…...

linux入门六:Linux Shell 编程

一、Shell 概述 1. 什么是 Shell&#xff1f; Shell 是 Linux 系统中用户与内核之间的桥梁&#xff0c;作为 命令解析器&#xff0c;它负责将用户输入的文本命令转换为计算机可执行的机器指令。 本质&#xff1a;Shell 是一个程序&#xff08;如常见的 Bash、Zsh&#xff09…...

Franka 机器人x Dexterity Gen引领遥操作精细任务新时代

教授机器人工具灵活操作难题 在教授机器人灵活使用工具方面&#xff0c;目前主要有两种策略&#xff1a;一是人类遥控&#xff08;用于模仿学习&#xff09;&#xff0c;二是模拟到现实的强化学习。然而&#xff0c;这两种方法均存在明显的局限性。 1、人类遥控&#xff08;用…...

网络通讯协议UDP转发TCP工具_UdpToTcpRelay_双向版

UDP/TCP网络转发器程序说明书 1. 程序概述 本程序是一个高性能网络数据转发工具&#xff0c;支持UDP和TCP协议之间的双向数据转发&#xff0c;并具备以下核心功能&#xff1a; 协议转换&#xff1a;实现UDP↔TCP协议转换数据转换&#xff1a;支持十六进制/ASCII格式的数据转…...

深入理解 RxSwift 中的 Driver:用法与实践

目录 前言 一、什么是Driver 1.不会发出错误 2.主线程保证 3.可重放 4.易于绑定 二、Driver vs Observable 三、使用场景 1.绑定数据到UI控件 2.响应用户交互 3.需要线程安全的逻辑 4.如何使用Driver&#xff1f; 1.绑定文本输入到Label 2.处理按钮点击事件 3…...

【XML基础-3】深入理解XML Schema:XML的强大语义约束机制

XML&#xff08;可扩展标记语言&#xff09;作为数据交换的标准格式&#xff0c;在当今信息技术领域扮演着重要角色。然而&#xff0c;仅有基本的XML语法规则往往不足以满足复杂的数据验证需求。这正是XML Schema发挥作用的地方——它为XML文档提供了强大的语义约束能力。本文将…...

神经网络语言模型与统计语言模型的比较

神经网络语言模型&#xff08;Neural Language Models, NLMs&#xff09;与统计语言模型&#xff08;Statistical Language Models, SLMs&#xff09;是自然语言处理&#xff08;NLP&#xff09;中两类核心的语言建模方法&#xff0c;其核心差异体现在建模方式、表示能力、数据…...

大模型论文:CRAMMING TRAINING A LANGUAGE MODEL ON ASINGLE GPU IN ONE DAY(效率提升)-final

大模型论文&#xff1a;CRAMMING: TRAINING A LANGUAGE MODEL ON ASINGLE GPU IN ONE DAY(效率提升) 文章地址&#xff1a;https://arxiv.org/abs/2212.14034 摘要 近年来&#xff0c;语言建模的研究趋势集中在通过大规模扩展来提升性能&#xff0c;导致训练语言模型的成本变…...

构建AI应用(持续更新)

常用的框架&#xff1a; dify、coze&#xff1a;低代码模块化编程 langchain&#xff1a;面向程序人员 常规的应用&#xff1a; 语音转文字ASR&#xff0c;文字转语音TTS&#xff0c;下一步问题建议&#xff0c; 旅游计划&#xff0c;买点提取&#xff0c;情感陪聊&#x…...

【JAVA】JVM 堆内存“缓冲空间”的压缩机制及调整方法

1. 缓冲空间是否可压缩&#xff1f; 是的&#xff0c;JVM 会在满足条件时自动收缩堆内存&#xff0c;将未使用的缓冲空间释放回操作系统。但需满足以下条件&#xff1a; GC 触发堆收缩&#xff1a;某些垃圾回收器&#xff08;如 G1、Serial、Parallel&#xff09;在 Full GC …...

NLP高频面试题(三十八)——什么是LLM的灾难性遗忘?如何避免灾难性遗忘?

近年来,大语言模型在人工智能领域取得了显著进展。然而,随着模型的不断更新和新任务的引入,出现了一个重要的问题,即灾难性遗忘(Catastrophic Forgetting)。灾难性遗忘指的是大模型在连续学习新知识或新任务时,先前掌握的旧知识会迅速被覆盖或遗忘,从而导致模型在旧任务…...

Keepalived+LVS高可用集群实战:从原理到落地

在分布式系统架构中&#xff0c;服务的高可用性和负载均衡是保障业务连续性的核心要素。本文通过一次实验&#xff0c;深入探索了基于KeepalivedLVS的高可用负载均衡集群方案&#xff0c;带您从零开始理解原理、动手实践配置&#xff0c;并验证其可靠性。 一、实验目标 本次实…...

【JVM】JVM调优实战

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…...

Linux系统安全-开发中注意哪些操作系统安全

Hey小伙伴们~&#x1f44b; 在Linux开发中&#xff0c;确保操作系统的安全真的太太太重要啦&#xff01;&#x1f6e1;️ 今天就来和大家聊聊几个超关键的注意事项&#xff0c;记得拿小本本记下来哦&#xff01;&#x1f4dd; 1️⃣ ‌用户管理与权限控制‌&#x1f465; 合理…...

Qt问题之 告别软件因系统默认中文输入法导致错误退出的烦恼

1. 问题 使用Qt进行研发时&#xff0c;遇到一个问题&#xff0c;当在系统默认输入法中文&#xff08;英文输入法或者搜狗就不会触发闪退&#xff09;的情况下&#xff0c;选中QTableWidget控件&#xff08;QTableWidgetItem有焦点&#xff0c;但是不双击&#xff09;&#xff…...

2025 年“认证杯”数学中国数学建模网络挑战赛 D题 无人机送货规划

在快递和外卖等短途递送小件货物的业务中&#xff0c;无人机或许大有可为。现 有一个城市的快递仓库准备使用若干无人机进行派件&#xff0c;设有若干架无人机从 仓库出发&#xff0c;分别装载了若干快递包裹。每架无人机装载的包裹的收货地点会 被排列为一个目的地列表&#x…...

【2025年认证杯数学中国数学建模网络挑战赛】A题解题思路与模型代码

【2025年认证杯数学建模挑战赛】A题 该题为典型的空间几何建模轨道动力学建模预测问题。 ⚙ 问题一&#xff1a;利用多个天文台的同步观测&#xff0c;确定小行星与地球的相对距离 问题分析 已知若干地面天文台的观测数据&#xff1a;方位角 (Azimuth) 和 高度角 (Altitude)&…...

Redhat红帽 RHCE8.0认证体系课程

课程大小&#xff1a;7.7G 课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/90546064 更多资源下载&#xff1a;关注我 红帽企业 Linux 系统的管理技能已经成为现代数据中心的核心竞争力。 Linux 在支持混合云、跨物理服务器、虚机、私有云和公共云计…...

Python 实现的运筹优化系统数学建模详解(最大最小化模型)

一、引言 在数学建模的实际应用里&#xff0c;最大最小化模型是一种极为关键的优化模型。它的核心目标是找出一组决策变量&#xff0c;让多个目标函数值里的最大值尽可能小。该模型在诸多领域&#xff0c;如资源分配、选址规划等&#xff0c;都有广泛的应用。本文将深入剖析最大…...

MySQL快速入门

MySQL快速入门 SQL语句 SQL语句概述 1.SQL 是用于访问和处理数据库的标准的计算机语言。 2.SQL指结构化查询语言&#xff0c;全称是 Structured Query Language。 3.SQL 可以访问和处理数据库。 4.SQL 是一种 ANSI&#xff08;American National Standards Institute 美国…...

离线安装 nvidia-docker2(nvidia-container-toolkit)

很多时候大家都有用docker使用gpu的需求&#xff0c;但是因为网络等原因不是那么好用&#xff0c;这里留了一个给ubuntu的安装包&#xff0c;网络好的话也提供了在线安装方式 安装 nvidia-docker2 1 离线安装 &#xff08;推荐&#xff09; unzip解压后进入目录 dpkg -i *.d…...

【自然语言处理】深度学习中文本分类实现

文本分类是NLP中最基础也是应用最广泛的任务之一&#xff0c;从无用的邮件过滤到情感分析&#xff0c;从新闻分类到智能客服&#xff0c;都离不开高效准确的文本分类技术。本文将带您全面了解文本分类的技术演进&#xff0c;从传统机器学习到深度学习&#xff0c;手把手实现一套…...

云原生运维在 2025 年的发展蓝图

随着云计算技术的不断发展和普及&#xff0c;云原生已经成为了现代应用开发和运维的主流趋势。云原生运维是指在云原生环境下&#xff0c;对应用进行部署、监控、管理和优化的过程。在 2025 年&#xff0c;云原生运维将迎来更加广阔的发展前景&#xff0c;同时也将面临着一系列…...

Windows系统Python多版本运行解决TensorFlow安装问题(附详细图文)

Windows系统Python多版本运行解决TensorFlow安装问题&#xff08;附详细图文&#xff09; 摘要 TensorFlow 无法安装&#xff1f;Python版本太高是元凶&#xff01; 本文针对Windows系统中因Python版本过高导致TensorFlow安装失败的问题&#xff0c;提供三种降级解决方案&…...

银行业务知识序言

银行业务知识体系全景解析 第一章 金融创新浪潮下的银行业务知识革命 1.1 数字化转型驱动金融业态重构 在区块链、人工智能、物联网等技术的叠加作用下&#xff0c;全球银行业正经历着"服务无形化、流程智能化、风控穿透化"的深刻变革。根据麦肯锡《2023全球银行业…...

《深度剖析分布式软总线:软时钟与时间同步机制探秘》

在分布式系统不断发展的进程中&#xff0c;设备间的协同合作变得愈发紧密和复杂。为了确保各个设备在协同工作时能够有条不紊地进行&#xff0c;就像一场精准的交响乐演出&#xff0c;每个乐器都要在正确的时间奏响音符&#xff0c;分布式软总线中的软时钟与时间同步机制应运而…...

RK3588 android12 适配 ilitek i2c接口TP

一&#xff0c;Ilitek 触摸屏简介 Ilitek 提供多种型号的触控屏控制器&#xff0c;如 ILI6480、ILI9341 等&#xff0c;采用 I2C 接口。 这些控制器能够支持多点触控&#xff0c;并具有优秀的灵敏度和响应速度。 Ilitek 的触摸屏控制器监测屏幕上的触摸事件。 当触摸发生时&a…...

pgsql:关联查询union(并集)、except(差集)、intersect(交集)

pgsql:关联查询union(并集)、except(差集)、intersect(交集)_pgsql except-CSDN博客...

模型材质共享导致的问题

问题&#xff1a;当我选中其中某个网格模型并设置color的时候&#xff0c;相同种类的颜色都被改变&#xff0c;但是打印我选中的网格模型数据其实只有一个。 导致问题的原因&#xff1a; 加载Blender模型修改材质颜色 Blender创建一个模型对象&#xff0c;设置颜色&#xff0…...

ThinkpPHP生成二维码

导入依赖 composer require endroid/qr-code 封装成函数&#xff0c;传入二维码包含的值&#xff0c;存储路径&#xff0c;二维码大小&#xff0c;二维码边距 private function getCode($content, $directory, $size 300, $margin 10){// 创建二维码对象// $content: 二…...

FLINK框架:流式处理框架Flink简介

在大数据时代&#xff0c;数据的价值不言而喻&#xff0c;谁能利用好数据&#xff0c;谁就掌握了整个行业的先机。面对海量的数据&#xff0c;如何处理数据成为了一个难题。除了海量数据外&#xff0c;实时性也是一个重要的课题&#xff0c;所以流式数据处理便登上了技术舞台&a…...

使用Python从零开始构建生成型TransformerLM并训练

在人工智能的浩瀚宇宙中&#xff0c;有一种神奇的生物&#xff0c;它拥有着强大的语言魔法&#xff0c;能够生成各种各样的文本&#xff0c;仿佛拥有无尽的创造力。它就是——Transformer 模型&#xff01;Transformer 模型的出现&#xff0c;为人工智能领域带来了一场“语言魔…...

xtrabackup备份

安装&#xff1a; https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/Percona-XtraBackup-8.0.35-30/binary/tarball/percona-xtrabackup-8.0.35-30-Linux-x86_64.glibc2.17.tar.gz?_gl1*1ud2oby*_gcl_au*MTMyODM4NTk1NS4xNzM3MjUwNjQ2https://downloads.perc…...

2.3 Spark运行架构与流程

Spark运行架构与流程包括几个核心概念&#xff1a;Driver负责提交应用并初始化作业&#xff0c;Executor在工作节点上执行任务&#xff0c;作业是一系列计算任务&#xff0c;任务是作业的基本执行单元&#xff0c;阶段是一组并行任务。Spark支持多种运行模式&#xff0c;包括单…...

【Pandas】pandas DataFrame head

Pandas2.2 DataFrame Indexing, iteration 方法描述DataFrame.head([n])用于返回 DataFrame 的前几行 pandas.DataFrame.head pandas.DataFrame.head 是一个方法&#xff0c;用于返回 DataFrame 的前几行。这个方法非常有用&#xff0c;特别是在需要快速查看 DataFrame 的前…...

从递归入手一维动态规划

从递归入手一维动态规划 1. 509. 斐波那契数 1.1 思路 递归 F(i) F(i-1) F(i-2) 每个点都往下展开两个分支&#xff0c;时间复杂度为 O(2n) 。 在上图中我们可以看到 F(6) F(5) F(4)。 计算 F(6) 的时候已经展开计算过 F(5)了。而在计算 F(7)的时候&#xff0c;还需要…...

鸿蒙HarmonyOS埋点SDK,ClkLog适配鸿蒙埋点分析

ClkLog埋点分析系统&#xff0c;是一种全新的、开源的洞察方案&#xff0c;它能够帮助您捕捉每一个关键数据点&#xff0c;确保您的决策基于最准确的用户行为分析。技术人员可快速搭建私有的分析系统。 ClkLog鸿蒙埋点SDK通过手动埋点的方式实现HarmonyOS 原生应用的前端数据采…...

HarmonyOS:HMPermission权限请求框架

前段时间利用空余时间写了一个权限请求库&#xff1a;HMPermission。 一&#xff0c;简介 HMPermission 是鸿蒙系统上的一款权限请求框架&#xff0c;封装了权限请求逻辑&#xff0c;采用链式调用的方式请求权限&#xff0c;简化了权限请求的代码。 二&#xff0c;使用方法 …...

【书籍】DeepSeek谈《持续交付2.0》

目录 一、深入理解1. 核心理念升级&#xff1a;从"自动化"到"双环模型"2. 数字化转型的五大核心能力3. 关键实践与案例4. 组织与文化变革5. 与其它框架的关系6. 实际应用建议 二、对于开发实习生的帮助1. 立刻提升你的代码交付质量&#xff08;技术验证环实…...

Spring AOP 扫盲

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

银河麒麟v10(arm架构)部署Embedding模型bge-m3【简单版本】

硬件 服务器配置&#xff1a;鲲鹏2 * 920&#xff08;32c&#xff09; 4 * Atlas300I duo卡 参考文章 https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d 鲲鹏昇腾Atlas300Iduo部署Embedding模型和Rerank模型并连接Dify&#xff08;自…...

如何通过流程管理优化企业运营?

流程管理的本质是“用确定性的规则应对不确定性的业务”。 那么&#xff0c;具体该如何通过流程管理来优化企业的运作呢&#xff1f;以下是一些关键步骤和思路&#xff0c;或许能给到一些启发。 1. 从流程梳理开始&#xff1a;摸清现状&#xff0c;找准问题 想要管理好企业的…...

ZYNQ笔记(四):AXI GPIO

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 任务&#xff1a;使用 AXI GPIO IP 核实现按键 KEY 控制 LED 亮灭&#xff08;两个都在PL端&#xff09; 一、介绍 AXI GPIO (Advanced eXtensible Interface General Purpose Input/Output) 是 Xilinx 提供的一个可…...

Java学习手册:JVM、JRE和JDK的关系

在Java生态系统中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;、JRE&#xff08;Java运行时环境&#xff09;和JDK&#xff08;Java开发工具包&#xff09;是三个核心概念。它们共同构成了Java语言运行和开发的基础。理解它们之间的关系对于Java开发者来说至关重要。本文…...