尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Harmony os 技术实战|拼豆制图47:时间戳只保住作品 ID,4900 个 Cell ID 仍会相撞

Harmony os 技术实战|拼豆制图47:时间戳只保住作品 ID,4900 个 Cell ID 仍会相撞 生成一张 70×70 的拼豆图时应用会创建 4900 个完整格子还可能创建一组缩略格子。很多实现只给作品 ID 加上时间戳却继续使用user-chart-行-列作为格子 ID。单张图里它们确实唯一但两张用户作品一旦进入同一个持久化集合或混合列表格子标识就会重复。本文从作品、完整格和预览格三个层级重新设计命名空间让 ArkUI 列表键、选择状态和后续记录恢复都指向同一个稳定实体。一、重复发生在“跨作品”而不是“单张图内部”固定前缀配合行列坐标在一张图中没有问题constcellIduser-chart-${row}-${column}但第二张图仍会从user-chart-0-0开始。只要业务出现以下任一变化冲突就会暴露最近生成记录同时保留多张完整图两张图被放进同一个对比视图选择状态使用Setstring记录格子 ID持久化恢复时以格子 ID 合并数据外层列表把多个图纸的格子扁平化渲染。因此格子 ID 的唯一范围不能只停留在数组内部而应覆盖一个作品集合的生命周期。二、先定义三层身份关系一个清晰的标识体系包含三层patternId一次生成作品chartCellId作品中的完整图格子previewCellId作品中的预览格子。推荐格式如下user-1723456789000-3 user-1723456789000-3:chart:12:18 user-1723456789000-3:preview:4:6冒号并非硬性要求真正重要的是每个子实体都携带父作品命名空间并且完整图和预览图拥有不同分区。三、同一毫秒也要避免作品 ID 重复单独使用Date.now()仍有边界连续调用可能落在同一毫秒。可以由进程内工厂补充递增序号exportclassGeneratedIdFactory{privatestaticlastTime:number0privatestaticsequence:number0staticnextPatternId(now:numberDate.now()):string{if(nowGeneratedIdFactory.lastTime){GeneratedIdFactory.sequence1}else{GeneratedIdFactory.lastTimenow GeneratedIdFactory.sequence0}returnuser-${now}-${GeneratedIdFactory.sequence}}staticchartCell(patternId:string,row:number,column:number):string{return${patternId}:chart:${row}:${column}}staticpreviewCell(patternId:string,row:number,column:number):string{return${patternId}:preview:${row}:${column}}}把now作为可选参数还有一个好处单元测试能够构造“同一毫秒连续生成”的稳定场景。四、先生成作品 ID再创建任何格子命名空间必须在转换开始时确定并贯穿所有派生数据。不要先造格子最后才给Pattern补 ID。privatestaticasyncbuildPattern(pixelMap:image.PixelMap,size:image.Size):PromisePattern{constpatternIdGeneratedIdFactory.nextPatternId()constsampledawaitImageConvertService.sampleColors(pixelMap,size)constchartCells:PatternCell[][]for(letrow0;rowsampled.height;row1){for(letcolumn0;columnsampled.width;column1){chartCells.push({id:GeneratedIdFactory.chartCell(patternId,row,column),row:row,column:column,color:sampled.colorAt(row,column)})}}returnPatternBuilder.fromCells(patternId,chartCells,sampled.width,sampled.height)}这样Pattern.id与每个PatternCell.id在创建时就完成绑定不会出现中途改名导致引用失效。五、预览格不能复用完整格 ID预览格通常由降采样或分块统计得到它的(row, column)与完整图坐标不是同一个空间。即便当前两个数组不会同时渲染也应使用独立分区functionbuildPreviewCells(patternId:string,blocks:PreviewBlock[]):PatternCell[]{returnblocks.map((block:PreviewBlock){return{id:GeneratedIdFactory.previewCell(patternId,block.row,block.column),row:block.row,column:block.column,color:block.dominantColor}})}如果直接复用完整格 ID未来加入“点击预览定位到原图”时很难判断一个 ID 表示原始坐标还是块坐标。六、ArkUI 的键要直接使用领域 ID列表键若继续拼数组下标就绕开了前面建立的身份体系。ForEach可以直接使用格子 IDForEach(this.pattern.chartCells,(cell:PatternCell){PatternCellView({cell:cell})},(cell:PatternCell)cell.id)当排序、局部更新或多个作品合并展示时稳定键能帮助框架准确识别节点。不要把颜色作为键因为同色格子天然大量重复也不要只用下标因为插入和过滤会改变位置。七、选择状态也要带作品边界如果状态只保存row-column切换作品后旧选择可能错误地落在新图上。可以保存完整格子 ID或显式保存复合引用exportinterfaceCellRef{patternId:stringcellId:string}functionsameCell(left:CellRef,right:CellRef):boolean{returnleft.patternIdright.patternIdleft.cellIdright.cellId}虽然cellId已包含patternId结构化引用仍能让调用方清楚地执行作品级过滤也方便序列化时校验父子关系。八、保存记录时校验父子一致性带命名空间不代表永远正确组装对象时仍可能把 A 图的格子误塞给 B 图。保存前增加一个轻量断言exportfunctionvalidateCellNamespace(pattern:Pattern):string[]{constissues:string[][]constchartPrefix${pattern.id}:chart:constpreviewPrefix${pattern.id}:preview:pattern.chartCells.forEach((cell:PatternCell){if(!cell.id.startsWith(chartPrefix)){issues.push(完整格命名空间不一致${cell.row},${cell.column})}})pattern.previewCells.forEach((cell:PatternCell){if(!cell.id.startsWith(previewPrefix)){issues.push(预览格命名空间不一致${cell.row},${cell.column})}})returnissues}这条校验适合放进仓库写入边界而不是散落在每个页面里。九、旧记录迁移不要原地猜测若本地已经保存固定前缀的旧数据可以在读取层识别版本并重建 IDexportinterfaceStoredPatternV2{schemaVersion:2pattern:Pattern}functionmigrateCellIds(pattern:Pattern):Pattern{constchartCellspattern.chartCells.map((cell:PatternCell)({...cell,id:GeneratedIdFactory.chartCell(pattern.id,cell.row,cell.column)}))constpreviewCellspattern.previewCells.map((cell:PatternCell)({...cell,id:GeneratedIdFactory.previewCell(pattern.id,cell.row,cell.column)}))return{...pattern,chartCells,previewCells}}迁移完成后写入新版本业务页面始终只接收 V2 数据。这样旧格式兼容不会渗透到渲染和编辑逻辑。十、用四组断言守住唯一性建议测试以下关系而不只是判断字符串非空constfirstGeneratedIdFactory.nextPatternId(1000)constsecondGeneratedIdFactory.nextPatternId(1000)expect(first).not().assertEqual(second)constaGeneratedIdFactory.chartCell(first,0,0)constbGeneratedIdFactory.chartCell(second,0,0)expect(a).not().assertEqual(b)constchartGeneratedIdFactory.chartCell(first,1,2)constpreviewGeneratedIdFactory.previewCell(first,1,2)expect(chart).not().assertEqual(preview)此外还要验证一张 70×70 图纸的 4900 个完整格 ID 去重后数量仍为 4900并验证两张图合并后的数量等于两者之和。十一、落地检查清单作品 ID 在同一毫秒连续生成时仍然不同完整格和预览格使用不同分区每个格子 ID 都包含所属作品 IDForEach直接使用领域 ID 作为键选择状态不会跨作品串联保存前校验父子命名空间旧记录只在读取边界迁移一次。验证时不要只检查字符串前缀还要把两张 70×70 图纸的完整格与预览格合并后统一去重。去重数量应等于四个数组长度之和再分别抽取首尾坐标确认所属作品与分区正确才能覆盖真实的跨作品场景。总结时间戳解决的是作品级身份行列坐标解决的是作品内部定位二者必须组合才能形成真正稳定的格子 ID。把作品命名空间贯穿完整格、预览格、列表键和持久化记录后当前 4900 个格子的渲染更可靠也为多作品对比、历史恢复和局部编辑留出了清晰边界。标签Harmony os、ArkTS、ArkUI、数据建模、稳定标识
返回列表