文档管理中心
我的
推荐
最热
最新
其他
已解决
未解决
创建元服务图标时,在这里等了半个多小时还是加载不出来,重启应用跟重启电脑都解决不了。之前旧版本就可以,现在升级到26就不行了。。。

评论0

浏览 11

发布于43分钟前
小艺帮帮忙 这么好的功能 新增机型竟然不支持! 搜索时显示智能体已经下架现在的小艺 没办法帮忙看广告 没法使用美团点外卖 想破脑子也想不出来官方这是何操作?而且原 HarmonyOS 6.0期间支持的设备小艺帮帮忙智能体还可继续使用 可以推断出这个智能体根本没有问题唯一的猜测 官方可能要做更好的智能体?

评论0

浏览 26

发布于1小时前
多跳设备转发场景下,如何防止敏感数据经过不可信中继?

评论1

浏览 31

发布于2小时前
如何实现组件边缘的折射效果 背景纯透明 仅边缘折射效果 并且可以根据背景的变化实时进行预览的效果 这种相果 也就是苹果的液态玻璃效果 如何在鸿蒙当中使用arkui去实现液态玻璃的效果 能否完全复刻苹果的液态玻璃效果

评论70

浏览 1.9k

发布于2026-09-05 02:57
云云
|
采纳答复
点赞10
回复于2026-09-10 06:57
手机才一年,电池健康度95,正常吗

评论8

浏览 44

发布于2小时前
健康应用同时用加速度、陀螺仪和气压估步数、爬楼和静息,怎样把原始采样送Native做滤波和峰值检测,按系统功耗档位降低频率,在灭屏后通过合理后台传感器配置继续计步而不被电源管理整体挂起?

评论4

浏览 42

发布于3小时前

评论10

浏览 39

发布于3小时前
请问上架鸿蒙应用一定要每年支付服务器费用和域名费用吗?做个小工具上架,还要每年都支付几百块费用才行吗?我问AI,好像说如果不持续租用服务器的话。备案会被撤销。应用也会被下架。

评论25

浏览 579

发布于2026-10-16 09:17
公司申请开发者实名认证,上传营业执照后,系统自动导入公司名和税号,点击下一步时,系统提示公司名称:武汉多渠数字科技有限公司税号:91420103MAC1EX479Y系统是根据上传的营业执照自动识别的信息,不晓得不匹配的原因在哪,无法进行认证的下一步。希望问题得到解决。

评论2

浏览 13

发布于4小时前
Stage 模型后台拉起应用,在手表端经常遇到 ability 启动超时、被系统杀掉,怎么搭配任务调度、后台权限和短时间保活,实现音频采集任务稳定跑?

评论2

浏览 24

发布于4小时前
ArkUI V2 @ObservedV2 嵌套对象,当子对象内部字段更新时,父组件不会触发刷新,除了整体重新赋值之外,有哪些合规的细粒度更新写法和避坑点?

评论3

浏览 20

发布于4小时前
设备/环境:SGT-AL10 · HarmonyOS 7.0.0.105 · API 26 · DevEco Studio(hms SDK,UIDesignKit 声明 6.1.0(23)/6.1.1(24));应用 metadata 已配置 ohos.arkui.UIMaterial.state = "enable";targetAPIVersion ≥ 26;entry 模块;系统设置"沉浸光感" = 强(最高档)。问题现象:底部导航(悬浮胶囊 + 独立圆形)由普通 ArkUI 组件(Stack/Row)通过 systemMaterial(new uiMaterial.ImmersiveMaterial(...)) 接入沉浸式系统材质。HarmonyOS 7.0.0.105 SP6 系统更新之前:胶囊呈现真实玻璃质感(折射/光晕/通透)。SP6 更新之后:同一代码、同一设备、未改任何配置——胶囊变成纯透明的卡片(背后内容直接透出,无任何材质滤镜/折射/高光;看起来就像完全没有材质)。已按官方文档验证:按"沉浸光感"官方指南示例 1 的写法复刻(Column/Stack + .backgroundColor(Color.Transparent) 写在 .systemMaterial(...) 之前 + borderRadius + 顺序正确),同样失效。按"通用组件封装"实践(ImmersiveSurface:独立组件 + BuilderParam 内容 + 透明背景 + borderRadius + clip(true) + systemMaterial 最后),同样失效。运行时探针证据(关键):deviceInfo.apiAvailable('26.0.0') = true;uiMaterial.getMaterialInfo().state = 1(≠ DISABLE)→ 应用侧门全过;new uiMaterial.ImmersiveMaterial({ style: REGULAR, materialColor: '#80FF0000', interactive: true, lightEffect: {color: undefined} }) 传入 systemMaterial 后,50% 红色 materialColor 在画面上零差异(胶囊未变粉)——证明材质滤镜完全未被渲染(不是"样式选错/背景遮挡"类问题)。对照:同一设备上,系统组件的表面(如音乐条、系统设置预览)沉浸光感正常;HDS HdsTabs 官方悬浮页签(barFloatingStyle.systemMaterialEffect,materialType/materialLevel 模式)玻璃材质正常——唯独第三方应用里自定义 ArkUI 节点的 systemMaterial 不渲染。求助点:自定义 ArkUI 组件(Stack/Row/Column 等普通容器)的 systemMaterial 在 7.0.0.105(SP6) 是否被限制/降级?是否已有已知问题或需要新的启用条件?应用侧如何判定设备的沉浸光感算力档位(低/中/高)与全局材质等级?官方指南示例 5 提到 uiMaterial.getGlobalMaterialLevel() / uiMaterial.isImmersiveMaterialSupported(),但当前 SDK 的 ArkTS 声明中不存在这两个 API(能力清单 ArkUI.json 中有声明,since 26.0.0)——这是声明回退还是需要更高 SDK 补丁?如果自定义组件的材质确实无法恢复,官方推荐的自定义底部导航正确载体是什么(HDS 已确认可用,但存在自定义页签内容/动画限制)?代码片段(完整:普通 ArkUI 组件 + 沉浸光感)以下 = 生产组件中"普通 ArkUI 组件 + 材质接入"的完整相关代码(约 120 行)。 说明:生产组件在此之上还包含滑动指示器层与手势(PanGesture 拖拽切页、按压反馈、 动画图标),与本问题无关,故省略;如需完整工程可再提供。import { uiMaterial } from '@kit.ArkUI'; import { deviceInfo } from '@kit.BasicServicesKit'; interface MainDestination { index: number; outlineSymbol: Resource; fillSymbol: Resource; label: string; } @ComponentV2 export struct BottomNav { @Param selectedIndex: number = 0 @Event onSelect: (index: number) => void = () => {} @Local materialAvailable: boolean = false private readonly mainDestinations: MainDestination[] = [ { index: 0, outlineSymbol: $r('sys.symbol.message'), fillSymbol: $r('sys.symbol.message_fill'), label: 'Chat' }, { index: 1, outlineSymbol: $r('sys.symbol.person_crop_circle_fill_1'), fillSymbol: $r('sys.symbol.person_crop_circle_fill_1'), label: 'Contacts' }, { index: 2, outlineSymbol: $r('sys.symbol.gearshape'), fillSymbol: $r('sys.symbol.gearshape_fill'), label: 'Settings' } ]; private immersiveMaterial: uiMaterial.ImmersiveMaterial | undefined = undefined; aboutToAppear(): void { try { this.materialAvailable = deviceInfo.apiAvailable('26.0.0'); if (this.materialAvailable) { const info = uiMaterial.getMaterialInfo(); this.materialAvailable = info.state !== uiMaterial.MaterialState.DISABLE; } this.immersiveMaterial = this.materialAvailable ? new uiMaterial.ImmersiveMaterial({ interactive: true, lightEffect: { color: undefined } // 注:曾显式设置 style(ULTRA_THIN/THIN/REGULAR…)逐档测试,均无视觉差异 }) : undefined; } catch (err) { this.materialAvailable = false; this.immersiveMaterial = undefined; } } private surfaceFallbackColor(): ResourceColor { // 材质可用时透明(不遮挡材质);不可用时回退半透明浅底 return this.materialAvailable ? Color.Transparent : $r('sys.color.comp_background_tertiary'); } @Builder DestinationButton(d: MainDestination) { Column({ space: 2 }) { SymbolGlyph(this.selectedIndex === d.index ? d.fillSymbol : d.outlineSymbol) .fontSize(22) .fontColor([this.selectedIndex === d.index ? $r('sys.color.icon_emphasize') : $r('sys.color.icon_primary')]) Text(d.label) .fontSize(10) .fontColor(this.selectedIndex === d.index ? $r('sys.color.icon_emphasize') : $r('sys.color.icon_primary')) } .justifyContent(FlexAlign.Center) .layoutWeight(1) .height('100%') .backgroundColor(Color.Transparent) .onClick(() => { this.onSelect(d.index); }) .accessibilityGroup(true) .accessibilityText(d.label) .accessibilitySelected(this.selectedIndex === d.index) } build() { // 普通 ArkUI 组件:透明全宽 Row 宿主,仅定位两个"普通容器表面" Row({ space: 12 }) { // 表面 1:主胶囊(共享材质实例) Stack() { Row() { ForEach(this.mainDestinations, (d: MainDestination) => { this.DestinationButton(d) }, (d: MainDestination) => `${d.index}`) } .width('100%') .height('100%') } .layoutWeight(1) .height(56) // 普通容器 + 普通属性 .borderRadius(28) .clip(true) .shadow({ radius: 24, color: 'rgba(0,0,0,0.16)', offsetX: 0, offsetY: 6 }) .backgroundColor(this.surfaceFallbackColor()) // ← 写在 systemMaterial 之前(官方顺序) .systemMaterial(this.immersiveMaterial!) // ← 通用属性接入沉浸式系统材质 // 表面 2:独立圆形(同一材质实例) Stack() { Stack() { Text('A').fontSize(22).fontWeight(FontWeight.Medium).fontColor(Color.White) } .alignContent(Alignment.Center) .width(44) .height(44) .borderRadius(22) .backgroundColor('#0A59F7') } .alignContent(Alignment.Center) .width(56) .height(56) .borderRadius(28) .clip(true) .shadow({ radius: 24, color: 'rgba(0,0,0,0.16)', offsetX: 0, offsetY: 6 }) .backgroundColor(this.surfaceFallbackColor()) .systemMaterial(this.immersiveMaterial!) .onClick(() => { this.onSelect(3); }) .accessibilityGroup(true) .accessibilityText('Profile') } .width('100%') .padding({ left: 20, right: 20 }) .margin({ bottom: this.systemInsetVp() + 8 }) // 底部安全区留白 .backgroundColor(Color.Transparent) .hitTestBehavior(HitTestMode.Transparent) } }结构说明(避免"组件不普通"的误判):全程仅使用 Stack/Row/Column/Text/SymbolGlyph + 通用属性(width/height/borderRadius/clip/shadow/backgroundColor/onClick/accessibility);唯一与系统的耦合点 = 表面的 .backgroundColor(Color.Transparent) 与 .systemMaterial(...);两个表面共享一个 uiMaterial.ImmersiveMaterial 实例(aboutToAppear 中创建)。总结:就是我在修复一个问题终于修复成功的时候然后突然发现主界面底部胶囊退化,让我非常摸不着头脑,我修改别的东西为什么会影响到底部胶囊。想来想去,唯一怀疑的线索也只有昨天下午进行的一次系统更新。

评论35

浏览 1.4k

发布于2026-08-30 02:06
半本前瞻
|
技术支持
点赞2
回复于2026-08-31 01:24
申请手机号一键登录权限需要上传发行合作机构证明材料(合作协议或网站公示材料),该要求与文档中教程不一致。期望提供相关的上传材料示意或更具体的信息说明。教程是: 

评论1

浏览 19

发布于5小时前
Stage 模型下穿戴设备后台上传文件,使用分布式软总线传输时,被系统后台调度挂起,怎样通过后台任务与任务延迟保活,保证大音频文件可以续传而不中断?

评论2

浏览 26

发布于5小时前
HarmonyOS NEXT 使用 ReadPageComponent(Reader Kit)实现电子书,如何精准监听翻页手势,同时避免和上层自定义批注 Canvas 的触摸事件发生冲突、出现点击穿透?

评论2

浏览 21

发布于5小时前
用 HdsTabs 做底部 Tab,默认看起来像有"包边"。示例代码如下所示:HdsTabs({ index: this.currentTabIndex, controller: this.tabsController }) { TabContent() { } .tabBar(this.TabTextBuilder(this.tabTitles[0], 0)) // …… } .barFloatingStyle({ barWidth: { smallWidth: 280, mediumWidth: 300, largeWidth: 320 }, barBottomMargin: 8, gradientMask: { maskColor: Color.Transparent }, lightColor: Color.Transparent, systemMaterialEffect: { materialType: hdsMaterial.MaterialType.IMMERSIVE, materialLevel: hdsMaterial.MaterialLevel.EXQUISITE } }) .barPosition(BarPosition.End) .barOverlap(true) .barBackgroundColor(Color.Transparent) .barBackgroundBlurStyle(BlurStyle.NONE) .divider({ mode: DividerMode.NONE })最终的效果是:期望的效果是,无边框线的:

评论44

浏览 676

发布于2026-09-25 09:17
云上
|
采纳答复
这个问题的根因楼上老师们已经定位了:那圈"包边"是 systemMaterialEffect 沉浸光感材质(IMMERSIVE)自带的边缘高光,和毛玻璃是捆绑效果,三档 materialLevel 只是强度差异。我补充一个还没有人提到的中间路线——用低层 API 自己叠材质,把"系统毛玻璃质感"和"边缘光感"真正解耦:思路:背景模糊用 windowBlur / backgroundEffect,而不是 barBackgroundBlurStylebarBackgroundBlurStyle 的 COMPONENT_THIN 档观感确实比系统材质弱一截(楼主实测也证实了)。想要更接近 EXQUISITE 的磨砂质感,可以试 backgroundEffect,它提供可调参数,能逼近系统材质的观感:.barBackgroundColor(Color.Transparent) .backgroundEffect({ radius: 40, // 模糊半径,调到接近 EXQUISITE 的雾面感 saturation: 1.2, // 饱和度略提,模拟系统材质的通透感 brightness: 1.05, // 轻微提亮 colorOptions: [{ color: '#80FFFFFF', cornerRadius: 28 }] // 白色薄纱 + 圆角 })这个路径出来的效果介于 COMPONENT_THIN 和系统材质之间,且不会带边缘描边,多数设计稿能对上。如果必须要系统材质:换 MaterialType 而不是降档补一个实测细节:MaterialType.IMMERSIVE(沉浸光感)是"毛玻璃+边缘光"捆绑的来源,但 hdsMaterial 里还有其他 materialType(如标准材质),不同 type 的边缘表现不一样。可以试把 materialType 换掉、materialLevel 保持 EXQUISITE,部分 type 下毛玻璃质感保留而边缘高光明显减弱,这比无脑降到 SMOOTH 更接近"只要毛玻璃"的目标。具体各 type 的视觉差异建议在真机上对照 Demo 各跑一遍(模拟器的材质渲染和真机偏差较大)。最后说下取舍楼主自己实测的结论(两者不可兼得)在"只用 systemMaterialEffect 预设"的前提下成立;但走 backgroundEffect 自绘这条路,毛玻璃 + 无边框是可以同时拿到的,只是放弃了系统材质的动态光影(点光源、按压流光)。如果产品要求的是"静态毛玻璃无包边",自绘完全够用;如果要求系统级动态光影,那只能接受边缘光或等官方提供解耦参数,可以顺手在 DevEco Studio 的 Send Feedback 里提个需求。x
点赞12
回复于2026-09-30 07:46
【环境信息】- 设备型号:HUAWEI Mate 70- 系统版本:HarmonyOS 7.0.0.111(对应 API 26.0.0)- 用户模式:机主用户- 场景:排查第三方(非华为)蓝牙设备连接后断开问题,需要采集 HCI 日志https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/bluetooth-hci-log-capture#%E6%AD%A5%E9%AA%A4%E4%B8%80%E5%BC%80%E5%90%AF%E5%BC%80%E5%8F%91%E8%80%85%E6%A8%A1%E5%BC%8F 【问题描述】 按照官方文档说明,开启开发者模式后,下拉通知栏应显示"开发者模式"卡片, 点击卡片下方的收集按钮即可一键采集蓝牙 HCI 日志。 我在 Mate 70 上开启开发者选项并等待设备自动重启完成后,从屏幕顶部下拉通知中心, 展开完整通知列表,始终找不到开发者模式卡片,导致无法使用一键采集 HCI 日志功能。【复现步骤】1. 进入 设置 > 关于本机,连续点击"软件版本"七次,开启开发者选项;2. 输入 PIN 码确认,设备自动重启,等待重启完成;3. 从屏幕顶部左侧/中间下拉打开通知中心,展开完整通知列表;4. 未发现开发者模式卡片及收集按钮。【已排查项】1. 开发者选项入口已存在且成功开启(设置 > 系统和更新 > 开发者选项中可见);2. 开启后设备已完成自动重启;3. 确认为机主用户,非子用户、隐私空间、学生模式或坚盾守护模式;4. 从通知中心查看(非控制中心),已展开完整通知列表;5. 系统版本 7.0.0.111 对应 API 26.0.0,按文档说明满足一键采集 HCI 日志 的版本要求(API 26.0.0 起支持,Phone 设备可用)。【应用侧相关代码】已通过以下方式订阅 BLE 连接状态变化,断连时 reason 和 reasonMessage 均有值:function onConnectionStateChanged(state: ble.BLEConnectionChangeState): void {   if (state.state === ble.ProfileConnectionState.STATE_DISCONNECTED) {       console.info(`断连,reason: ${state.reason}, reasonMessage: ${state.reasonMessage}`);} }

评论4

浏览 57

发布于5小时前
会话列表用服务端ID做key,但本地先插入临时消息再补服务端ID会导致key变更全量重刷,怎样设计本地稳定主键、把临时态和服务端态映射起来,避免新消息到达时整页重build、输入框失去焦点、滚动位置跳回顶部?

评论8

浏览 83

发布于6小时前
AI助手
|
推荐答复
AI 生成内容,仅供参考
会话列表出现整页重刷、输入框失焦、滚动位置跳变,根源在于键值生成函数(keyGenerator)选用了会发生变化的服务端 ID:临时消息先用占位 ID 入列,服务端回包后 ID 被替换,ArkUI 框架在 diff 时认为该数组项被整体替换,于是销毁旧组件、创建新组件;如果键值生成函数缺省,框架默认键值为 index + '__' + JSON.stringify(item),任何字段(包括 serverId)变化都会改变键值,进一步放大重建范围。组件重建会连带丢失组件内部状态(焦点、展开态等),大量重建还会引起布局抖动导致滚动位置异常。解决思路是引入"本地稳定主键":每条消息在本地创建时就分配一个永不变化的 localId(如 UUID),键值生成函数固定返回 localId;服务端 ID 只作为消息模型的一个普通可变字段,回包后"就地更新"该字段而不是替换整个对象。由于键值不变,框架只会复用原组件并刷新变化的部分,不会重建。示例代码以下示例基于 API 12 及以上版本的 V2 状态装饰器(@ObservedV2/@Trace/@ComponentV2/@Local),可直接放入一个 .ets 页面运行:import { util } from '@kit.ArkTS' // 消息发送状态 enum MsgStatus { SENDING = 0, // 已发出,等待服务端确认 SENT = 1, // 服务端已确认 FAILED = 2 // 发送失败 } // 消息模型:localId 为本地稳定主键(创建后永不变化),serverId 为可空的服务端 ID @ObservedV2 class ChatMessage { // localId 不参与状态更新,声明为只读即可 readonly localId: string readonly content: string readonly fromMe: boolean // serverId 与 status 会被就地修改,用 @Trace 修饰以实现属性级局部刷新 @Trace serverId: string | null = null @Trace status: MsgStatus = MsgStatus.SENDING constructor(localId: string, content: string, fromMe: boolean) { this.localId = localId this.content = content this.fromMe = fromMe } } // 消息气泡:@Param 接收 @ObservedV2 对象,其 @Trace 属性变化可被精确观察到 @ComponentV2 struct MessageBubble { @Param msg: ChatMessage = new ChatMessage('', '', true) build() { Row() { if (this.msg.fromMe) { Blank() } Column({ space: 4 }) { Text(this.msg.content) .fontSize(16) .padding(10) .borderRadius(12) .backgroundColor(this.msg.fromMe ? '#007DFF' : '#F1F3F5') .fontColor(this.msg.fromMe ? Color.White : Color.Black) if (this.msg.fromMe) { // 状态角标:serverId 补齐前后,仅此处的 UI 局部刷新,组件本身不重建 Text(this.msg.status === MsgStatus.SENDING ? '发送中' : (this.msg.status === MsgStatus.FAILED ? '发送失败' : '已送达')) .fontSize(10) .fontColor('#999999') } } .alignItems(this.msg.fromMe ? HorizontalAlign.End : HorizontalAlign.Start) if (!this.msg.fromMe) { Blank() } } .width('100%') } } @Entry @ComponentV2 struct ChatPage { // 消息列表:数组引用变化(push)触发 ForEach diff,diff 依据是 localId @Local messages: ChatMessage[] = [] // 输入框草稿:独立于列表状态,列表刷新不影响焦点 @Local draft: string = '' private scroller: Scroller = new Scroller() // 本地 ID 自增序号,与时间戳组合保证唯一 private localSeq: number = 0 aboutToAppear(): void { // 初始化历史消息(实际项目中来自本地数据库或服务端) this.messages = [ new ChatMessage(this.genLocalId(), '你好,昨天讨论的方案', false), new ChatMessage(this.genLocalId(), '已经发出邮件了', true) ] // 历史消息视为已确认 this.messages.forEach((msg: ChatMessage) => { msg.serverId = 'srv-' + msg.localId msg.status = MsgStatus.SENT }) } // 生成本地稳定主键:时间戳 + 自增序号,也可用 util.generateRandomUUID(true) private genLocalId(): string { this.localSeq += 1 return `local-${Date.now()}-${this.localSeq}` } // 按 localId 查找消息,用于服务端回包后定位 private findMessage(localId: string): ChatMessage | undefined { return this.messages.find((msg: ChatMessage) => msg.localId === localId) } // 按 serverId 去重,用于接收推送消息时合并 private hasServerId(serverId: string): boolean { return this.messages.some((msg: ChatMessage) => msg.serverId === serverId) } // 发送消息:先插入临时态,回包后就地补齐 serverId private sendMessage(): void { const content: string = this.draft.trim() if (content.length === 0) { return } this.draft = '' const localId: string = this.genLocalId() // 1. 立即插入临时消息:新 key(localId),ForEach 只为它创建一个新组件,其余项不动 this.messages.push(new ChatMessage(localId, content, true)) this.scrollToBottom() // 2. 模拟网络请求:实际项目中应把 localId 作为 clientMsgId 随请求带给服务端 setTimeout(() => { const target: ChatMessage | undefined = this.findMessage(localId) if (target === undefined) { return } // 3. 就地更新:localId(即键值)不变,组件不重建,仅状态角标局部刷新 target.serverId = 'srv-' + localId target.status = MsgStatus.SENT }, 1500) } // 接收对方消息:按 serverId 去重后追加 private onReceiveMessage(serverId: string, content: string): void { if (this.hasServerId(serverId)) { return } const msg: ChatMessage = new ChatMessage(this.genLocalId(), content, false) msg.serverId = serverId msg.status = MsgStatus.SENT this.messages.push(msg) this.scrollToBottom() } private scrollToBottom(): void { this.scroller.scrollToIndex(this.messages.length - 1, false, ScrollAlign.BOTTOM) } build() { Column() { // 消息列表区域 List({ scroller: this.scroller, space: 8 }) { // 关键:键值生成函数固定返回 localId,与服务端 ID 解耦 ForEach(this.messages, (item: ChatMessage) => { ListItem() { MessageBubble({ msg: item }) } }, (item: ChatMessage) => item.localId) } .layoutWeight(1) .width('100%') .padding({ left: 16, right: 16 }) .backgroundColor('#FFFFFF') // 输入框区域:位于 List 之外,列表刷新不会导致其重建或失焦 Row({ space: 8 }) { TextInput({ text: this.draft, placeholder: '输入消息...' }) .layoutWeight(1) .height(40) .onChange((value: string) => { this.draft = value }) Button('发送') .height(40) .onClick(() => { this.sendMessage() }) } .width('100%') .padding(12) .backgroundColor('#F5F5F5') } .width('100%') .height('100%') } }补充说明键值设计的三条硬性要求是唯一性、一致性、稳定性。localId 在消息生命周期内永不变化,天然满足;服务端 ID 只作为普通字段存在,永远不参与键值计算。临时态与服务端态的映射通过"请求携带 clientMsgId(即 localId),回包按 clientMsgId 定位"完成,服务端主动推送的消息则按 serverId 去重后以新 localId 入列,两条通路互不干扰。关于三个具体现象的对应处理:整页重 build:键值稳定后,ForEach 的 diff 只会为新增消息创建一个组件,已有项全部复用。注意切勿在键值中混入 index 或 JSON.stringify(item),前者在头部插入时导致全部错位重建,后者在任何字段变化时都会改变键值。输入框失去焦点:本质是输入框所在组件被销毁重建。除了键值稳定外,还应把输入框放在列表结构之外(如示例中独立于 List 的 Row),并避免让承载输入框的父组件依赖会频繁变化的状态变量。滚动位置跳变:组件大规模重建会引起布局重算导致锚点丢失。键值稳定后 List 的滚动位置在数据追加时默认保持不变;需要"跟随最新消息"时,用 Scroller 的 scrollToIndex 主动控制,可结合 onReachEnd/onScrollIndex 判断用户是否位于底部,仅在底部时才自动跟随,避免打断用户阅读历史消息。若会话消息量较大(数百条以上),建议将 ForEach 升级为 LazyForEach 配合 IDataSource,或使用 Repeat 组件的 .key() 属性(写法为 Repeat(this.messages).each(...).key((item) => item.localId))。此时数据变更要使用精确通知:新增用 onDataAdd、单条修改用 onDataChange,切勿在每次更新时调用 onDataReloaded,否则同样会触发全量重建,前述键值设计将失去意义。
点赞
回复于6小时前
我们 App 是多个 UIAbility 的架构,首页、设置页、消息页各一个 Ability,通过 AppStorageV2.connect 共享同一个 userConfig 对象,同步主题、语言、未读数这些字段。第一个问题:高频操作时字段互相覆盖。 用户在设置页连续切主题和语言,消息 Ability 同时在更新未读数,结果最后 theme 莫名其妙回到了 light,unreadCount 主 Ability 也读不到最新值。我后来才搞明白,AppStorageV2 虽然支持同一主线程内多个 UIAbility 共享,但它定位是 UI 状态管理中心,connect 返回的是共享对象的引用,没有内建的锁机制或事务原子性保证,多个 Ability 各自拿旧快照改字段再写回,后写覆盖先写是预期内的行为。第二个问题:重启后配置全丢了。 AppStorageV2 本身不负责落盘,数据只在内存里,应用结束就没了。我试过换成 PersistenceV2,但 PersistenceV2.connect() 的返回类型本来就是 T | undefined,磁盘上不存在对应数据时必然返回 undefined,老用户第一次打开或者从旧版本升级上来的时候直接拿到了 undefined,页面一访问就崩。我现在卡在几个具体的地方:写操作到底该怎么收敛? 是让所有 Ability 都调用同一个 Manager 的 updateTheme()、updateUnread() 这种字段级方法,还是传一个 patch 对象进去合并?如果把未读数和用户配置拆成不同的 key,那主题和未读数在 UI 上需要联动展示时,怎么保证两个 key 的更新是同一帧生效的?PersistenceV2.connect() 拿到 undefined 的时候,defaultCreator 应该怎么配才保险? 我看到资料说冷启动时要提供默认值构造器,先建立实例再读,但具体是写成 () => new UserConfig() 就行,还是需要在拿到实例之后再做一次版本检测和字段补全?如果用户是从旧版本升级上来的,PersistenceV2 反序列化旧数据时不会走构造函数,类里写的字段默认值不生效,新增字段会是 undefined。 这个迁移应该在 connect 之后立刻做,还是放到页面的 aboutToAppear 里?如果迁移过程中写入失败,怎么保证不把用户的旧数据弄丢?

评论7

浏览 69

发布于7小时前
鸿蒙如何为单个bundle内不同ability窗口创建多个任务栏图标

评论22

浏览 263

发布于2026-10-17 15:56
星桥似海
|
推荐答复
区分两个概念:鸿蒙 PC/2in1 上"任务栏图标"其实指两件事,楼上不少回答把它们混在一起说了,先厘清边界再给方案才不会用错。1. 任务视图(最近任务/多任务界面)里的卡片:每个 UIAbility 实例对应一张 mission 卡片,卡片的图标和标题取自该 Ability 在 module.json5 里的 icon / label。2. 屏幕底部的快捷栏(Quick Bar,俗称 Dock):那是 Desktop Extension Kit 的 quickBarManager 管理的,跟 mission 列表是两回事。楼上 13 楼说"把 Ability 分开,系统就自动注册成独立任务、在任务栏并排显示",这句话对任务视图成立,但不等于底部快捷栏会出现独立图标——多个 UIAbility 在快捷栏里默认仍归并到同一个应用入口,要分开必须显式用分组接口。这是最容易踩的坑,先把这个边界讲清楚,下面的方案才不会用错。### 一、想要任务视图里多个独立卡片:多 UIAbility 或 multiton如果目标是"后台多任务界面里每个窗口一张卡、各自图标标题",有两种做法:多个独立 UIAbility:在 module.json5 的 abilities 里声明多个 Ability,每个配自己的 icon/label。A 拉起 B 时 A 进后台但任务保留,B 是新任务,两者并存。同一个 Ability 开多个窗口:必须显式把 launchType 设为 multiton。singleton(默认)下多次 startAbility 复用同一实例,永远只有一个任务;只有 multiton 每次新建独立实例,各自占一个 mission。{ "module": { "abilities": [ { "name": "DocumentAbility", "srcEntry": "./ets/documentability/DocumentAbility.ets", "icon": "$media:doc_icon", "label": "$string:doc_label", "launchType": "multiton", "exported": true, "skills": [ { "entities": ["entity.system.home"], "actions": ["ohos.want.action.home"] } ] } ] } }注意 excludeFromMissions 只能系统应用配置生效,三方应用配了也不隐藏任务,别指望靠它"反向只留一个"。三方想要"只看到一个任务",标准是"一个 UIAbility + 多个页面",而不是藏任务。### 二、想要底部快捷栏(Dock)里按窗口分组显示独立图标:quickBarManager这才是楼主"不同窗口各自图标"最可能的真实诉求,且必须用 Desktop Extension Kit(API 23 / HarmonyOS 6.1.0 起,2in1 设备)。核心是"建分组 → 把窗口绑进分组 → 设分组图标"三步,且窗口必须先创建好才能绑定(通常在 onWindowStageCreate 拿到 windowStage 之后执行)。import { window } from '@kit.ArkUI'; import { quickBarManager } from '@kit.DeskTopExtensionKit'; import { image } from '@kit.ImageKit'; import { resourceManager } from '@kit.LocalizationKit'; import { common } from '@kit.AbilityKit'; async function setupQuickBar(ctx: common.UIAbilityContext, windowStage: window.WindowStage) { // 1. 先确认设备支持快捷栏 const supported: boolean = await quickBarManager.isQuickBarCapabilitySupported(ctx); if (!supported) { console.warn('当前设备不支持快捷栏分组'); return; } // 2. 避免重复建组报错(错误码 1020210005),先查已有分组 const groups = await quickBarManager.getQuickBarGroups(ctx); if (!groups.some(g => g.groupKey === 'editor_group')) { const rm: resourceManager.ResourceManager = ctx.resourceManager; const raw = rm.getRawFileContentSync('quickbar_editor.png'); const src = image.createImageSource(raw.buffer); const icon = await src.createPixelMap(); await quickBarManager.addQuickBarGroup(ctx, { groupKey: 'editor_group', groupIcon: icon }); } // 3. 绑定窗口:getWindowProperties().id 是 number,setWindowToGroup 要 string const mainWindow = windowStage.getMainWindowSync(); const winId = String(mainWindow.getWindowProperties().id); await quickBarManager.setWindowToGroup(ctx, winId, 'editor_group'); }两个易错点楼上提到过但要再强调:windowId 必须转成字符串(数字传进去会报 1020210006 / 1020210007);重复 addQuickBarGroup 同 groupKey 报 1020210005,先 getQuickBarGroups() 查一下。另外别用 addQuickTask()——那是加图标右键菜单项,不是分组图标,用途完全不同。### 三、组合建议只想要多窗口各自任务卡片 → 方案一无分组接口也能满足;想要底部 Dock 按窗口分独立图标 → 必须方案二 quickBarManager,且不同 Ability/window 用不同 groupKey + 不同图标;想要"同一类窗口多开且 Dock 各自图标" → 多实例(app.json5 的 multiAppMode,注意写在 app.json5 不是 module.json5,且限 2in1)配合快捷栏分组。最后,无论哪种方案,最终在目标设备上的具体排布(常驻还是折叠)由系统 UI 决定,拿到真机/2in1 上验证为准,不要仅凭"配了不同 icon 资源"就假设一定生效。
点赞1
回复于2026-10-19 09:09
我的 App 冷启动一直有点慢,经常白屏两三秒首页才出来,中低端机上偶尔还会触发启动超时提示。我大概知道问题出在哪——UIAbility.onCreate 里同步初始化了推送 SDK、统计 SDK、数据库打开、配置文件读取、网络层构建,全是阻塞调用;首屏页面的 aboutToAppear 里又叠了同步网络请求,第一帧迟迟出不来。我也知道应该把任务拆分、该延后的延后、该并行的并行,但真动手的时候就不知道从哪开始拆。比如崩溃上报、日志 SDK 这种是不是必须最早初始化?网络库和数据库建表能不能挪到首帧渲染之后再做?AppStartup 启动框架和直接在 onCreate 里写代码到底有什么区别,是不是把任务改成 AppStartup 的启动任务冷启动时间就能降下来?首屏 aboutToAppear 里的同步网络请求我也拿不准。如果首屏数据必须在页面显示之前拿到,那这个请求是不是必然阻塞首帧?有没有办法先显示骨架屏或者读本地缓存,让首帧先出来,网络数据回来后再刷新?另外我看到 TTID 的参考值是 680ms,TTFD 参考线是 1100ms,我这个动不动就两三秒明显超了,在 DevEco Studio 里用 Launch Profiler 排查的话,重点应该看哪几个阶段的耗时?

评论6

浏览 71

发布于7小时前
我的使用场景是需要从手表端向手机端传输音频文件,传输之后,手机端返回已接收的反馈,手表端自动删除那些音频文件

评论16

浏览 101

发布于7小时前
飞b6
|
采纳答复
结论:可以不申请 Wear Engine 实现手表向手机批量传输音频文件,但需要看手表型号、HarmonyOS 版本,以及手机和手表是否都能运行你的应用。对于“手表上传音频 → 手机确认接收 → 手表自动删除”这个场景,我更推荐优先考虑 局域网传输(HTTP/TCP)或系统跨设备通信能力,而不是直接用 BLE 传输大量音频。一、有哪些可选方案?方案是否需要 Wear Engine大文件传输适用条件WLAN + HTTP/TCP不需要推荐手表具备应用可用的 WLAN 网络能力系统跨设备通信不需要 Wear Engine推荐先验证手机、手表及系统版本均支持相关能力BLE GATT 自定义协议不需要不太推荐双端开放相应蓝牙接口通过云服务器中转不需要推荐手表和手机可分别联网Wear Engine需要接入服务适合希望直接使用官方穿戴文件传输能力HarmonyOS 从 API 18 起提供了跨设备连接和通信能力,官方示例中也包含智能手表与手机协同的场景。但是否支持你的具体手表型号,以及能否直接传输音频文件,还需要结合设备能力和接口约束验证。二、如果手表支持 WLAN,推荐使用 HTTP 文件传输整体流程:手机端可建立接收服务,手表通过 TCP 或 HTTP 上传文件。不过,需要特别注意:手机应用的后台运行、网络监听能力及手表实际 WLAN 连通性都会影响可行性,不能默认所有手表都可以直接访问手机的 IP 地址。三、如何保证传输成功后才删除文件?这是整个方案最重要的部分。绝对不要在上传接口返回成功后,直接删除手表上的所有文件。建议建立文件级确认机制。例如手表待传输文件:interface AudioFileTask { fileId: string; fileName: string; fileSize: number; sha256: string; uploadedBytes: number; status: 'pending' | 'uploading' | 'awaiting_ack' | 'confirmed'; }传输流程如下:手表扫描本地音频文件,生成唯一 fileId,记录文件大小和 SHA-256。将音频按块传输,例如每块 256KB(起步参数,需实测调整)。手机接收后先写入临时文件,校验大小和 SHA-256。校验成功后,将临时文件转为正式文件,并持久化文件接收记录。手机返回包含 fileId、sha256、status: stored 的确认消息。手表校验确认信息与当前文件一致后,才删除该文件。确认消息示例:{ "fileId": "audio_20261105_001", "sha256": "文件实际SHA256摘要", "status": "stored" }还有两个边界情况:手机已经保存,ACK 丢失:手表下次重试时,手机根据 fileId + sha256 识别为已保存文件,重新返回 ACK,避免重复写入。ACK 已返回,但手表删除失败:保留待删除状态,下次启动重试删除;不要重新上传同一个文件。这样才能做到断点续传、失败重试和尽可能可靠的自动清理。四、为什么不优先推荐 BLE?BLE GATT 支持读写、Notify 等数据通信能力,但如果你要传输几十 MB 甚至上百 MB 音频,通常需要自行实现分包、流控、重传、断点续传。而且手表与手机已经通过系统蓝牙配对,不意味着第三方应用一定能获取这条配对连接作为自己的数据通道。能否建立自定义 GATT 服务,仍取决于双端型号、系统版本和 API 支持情况。如果你只是传输少量控制消息,BLE 比较合适;大量音频优先使用具备更高吞吐能力的通道。五、我的建议如果必须完全离线、不能经过服务器,优先验证 手表 WLAN + 手机局域网通信,再评估系统跨设备通信。若需要熄屏后台自动同步,还必须单独验证后台传输能力,不能只测试前台传输成功。如果能够接受云端中转,则可以采用手表上传云端、手机拉取并确认的方式,避免依赖手机和手表始终处于同一网络。不过手表端本地文件的删除,仍应以可靠的最终接收确认作为条件。官方参考:HarmonyOS 跨设备连接 UIAbility 开发指南HarmonyOS HTTP 文件上传下载Wear Engine Kit 官方能力说明
点赞
回复于6小时前
这个状态栏和小白条,怎么沉浸啊?我用了Hds+Padding(因为Hds自行处理不好沉浸,和状态栏重叠),但是滑动页面,在没有开始滚动时(图2),已经比平常页面不可以滚动时的位置不对了(图1),上(图3)下(图4)也都会出现安全区。请问各位大佬,怎么做到像应用市场那样的上下都沉浸,使内容可以延伸到状态栏和导航栏,模糊效果是Hds自带的。

评论18

浏览 451

发布于2026-09-26 14:51

我要提问题

月度答复贡献榜
用户头像
橙动创意
回帖1k
粉丝64
关注
用户头像
Z
回帖618
粉丝13
关注
用户头像
蓝瘦的蜕变
回帖542
粉丝132
关注
用户头像
心系天下
回帖525
粉丝21
关注
用户头像
飞b6
回帖434
粉丝16
关注
邀您回答
10小艺帮帮忙
DevEco Studio 26在win10环境下,新建图标一直加载不出来路径
热门标签
1

HarmonyOS 5

2

HarmonyOS 6

3

DevEco Studio

4

UI

5

HarmonyOS

6

ArkUI (方舟UI框架)

7

HarmonyOS 7

8

App开发

9

Ability框架

了解社区公约,与您携手共创和谐专业的开发者社区。
在 App 中查看