资讯动态

HarmonyOS 7.0 文搜图实战⑤:从功能到交付【鸿蒙心迹】

发布时间:2026/10/24 2:13:16 来源:尧图企业网站定制
关于「一句找图」这个工具我们在前四篇已经解决不少积累的问题积累了。图片复制到应用沙箱操作进度写入清单平台调用串行执行搜索结果与提交的查询绑定。现在需要把这些结果放到最终的交付里让它们成为工程的一部分。这篇会是文搜图实战的收官篇不会增加新的业务逻辑。我们仍会沿用之前的业务设定。接下来的工作是让每个动作有负责的模块每次失败有可以追踪的原因每项改动有可以重复执行的检查。图1最终页面延续独立搜索按钮、导入入口和双列卡片结果区明确标出本次查询。1. 整理代码最初把代码写在页面里很自然按钮触发入库入库完成后更新状态再执行搜索。但当页面同时负责复制文件、保存清单和恢复服务时一次界面调整也可能碰到数据处理逻辑。修改范围开始超出问题本身。拆分应该围绕变化原因进行。布局变化留在页面文件访问变化留在文件模块平台接口变化集中在服务适配层。沿用前文名称可以把代码整理到以下位置entry/src/main/ets/ pages/Index.ets models/GalleryItem.ets models/SearchState.ets services/SearchCoordinator.ets services/SearchService.ets services/SearchMetrics.ets repositories/GalleryStore.ets files/ImageFiles.etsIndex展示状态并提交用户意图。ImageFiles管理应用持有的图片副本GalleryStore保存条目及重建进度。SearchMetrics记录第四篇定义的测量边界不改变搜索行为。SearchCoordinator负责连接这些步骤何时允许搜索何时等待文件准备何时转入恢复以及页面关闭后怎样结束服务会话。它不关心按钮圆角却必须知道当前是否还有平台调用没有结束。拆出文件并不会自动带来边界。页面如果仍能绕过协调器直接调用textSearchImage串行规则就只是约定。工程整理时需要检查调用关系让平台调用只沿一条路径发生。2. 平台适配和协调器为官方接口增加一个应用侧接口便于把真实调用与可控制的测试替身交换使用import{textSearchImage}fromkit.CoreVisionKit;exportinterfaceVisionPort{init():Promiseboolean;insertImage(path:string,scope:string):Promiseboolean;search(query:string,scope:string,topKey:number):PromisetextSearchImage.ImageObject\[];deleteImage(path:string,scope:string):Promiseboolean;clearData():Promiseboolean;release():Promiseboolean;}exportclassSearchServiceimplementsVisionPort{init():Promiseboolean{returntextSearchImage.init();}insertImage(path:string,scope:string):Promiseboolean{returntextSearchImage.insertImage(path,scope);}search(query:string,scope:string,topKey:number):PromisetextSearchImage.ImageObject\[]{returntextSearchImage.search(query,scope,topKey);}deleteImage(path:string,scope:string):Promiseboolean{returntextSearchImage.deleteImage(path,scope);}clearData():Promiseboolean{returntextSearchImage.clearData();}release():Promiseboolean{returntextSearchImage.release();}}这一层有意保持简单。布尔结果原样返回异常继续向调用方传播。官方接口的false需要处理抛出的错误也需要处理将它们都转为空数组会使调用失败看起来像正常的空结果。重试和重建由协调器决定。错误1013100003需要进入第三篇的恢复流程适配层不能在捕获异常后自行clearData()。它不知道哪些图片仍应保留也不知道是否存在尚未完成的移除操作。这也是接口抽象的价值变化发生在平台调用方式时调整适配层变化发生在应用策略时调整协调器。无需让所有模块一起理解平台错误。图2左侧目录表达职责编辑区集中展示平台适配手机界面保持既有布局。3. 状态所有者前三篇留下的图片条目状态和第四篇的搜索页面状态回答的是不同问题。把它们都压成一个ready只会让条件判断越来越难解释。状态由谁管理表达什么图片条目与重建批次GalleryStore已持久记录的业务进度当前调用与服务生命周期SearchCoordinator是否可以接受下一项工作草稿、提交查询和结果页面会话用户正在编辑或查看什么图库版本与人工评测评测资料一次比较采用了什么条件清单里的ready表示应用记录过入库成功不单独证明服务当前一定存在记录。反过来一次查询返回图片也不能证明整个清单已经恢复。第三篇的不确定窗口仍然存在不会因为重新组织文件就消失。持久状态记录恢复所需的事实内存状态描述本次运行。baseline-v1用于复现实验galleryRevision用于判断请求是否过期它们不应互相替代。新进程可以创建新的会话编号却必须读取已有清单不能把内存重置当作图库重置。同样clearData()没有 scope 参数不能写成只清理demo01。恢复时保留应用图片按第三篇的批次计划重新处理排除带有删除意图的条目。 普通启动不能为了省掉判断而先清空一次。4. 页面离开处理第四篇通过 ticket 阻止旧结果更新页面。这里再补齐另一半旧请求失去回写资格后平台调用仍可能正在执行。新页面不能同时开始初始化旧页面也不能立即释放它正在使用的服务。关闭顺序应当固定停止接收任务等待已接受工作结束再释放服务。同一次会话重复收到关闭通知时返回同一个 Promise。下面的结构保存于共享协调器中drained是已接受任务的完成屏障任务错误先被记录和处理屏障在任务结束后兑现。typeServicePhaseidle|ready|uncertain;interfaceCloseState{accepting:boolean;phase:ServicePhase;drained:Promisevoid;closing:Promisevoid|undefined;}functioncloseSession(state:CloseState,port:VisionPort):Promisevoid{state.acceptingfalse;if(state.closing!undefined){returnstate.closing;}state.closingfinishClose(state,port);returnstate.closing;}asyncfunctionfinishClose(state:CloseState,port:VisionPort):Promisevoid{awaitstate.drained;if(state.phaseidle){return;}if(state.phaseuncertain){thrownewError(服务状态需要核对);}try{constreleasedawaitport.release();if(!released){thrownewError(释放服务返回 false);}state.phaseidle;}catch(error){state.phaseuncertain;throwerror;}}协调器接受每项任务时必须在首个await前登记它并更新完成屏障。关闭过程不再接受后续任务因此等待范围是确定的正在结束的初始化任务也要先更新服务状态屏障才算完成。新会话通过同一协调器等待关闭完成。成功后才清理旧会话的closing并开始新的生命周期失败时保留原因不能无条件恢复接收任务。页面生命周期钩子发起关闭后也需要捕获拒绝并记录不能留下未处理的异步异常。release()释放服务资源不承担清空检索数据的责任。页面离开时使 ticket 失效服务收尾时完成资源管理这两件事分别执行才能同时保护界面和调用顺序。图3需要恢复时保持搜索与导入不可用恢复完成后再开放操作。5. 故障记录“搜索失败”对用户可能足够对接手工程的人却不够。同一个现象可能来自初始化、图片文件、清单提交或服务调用。记录应当包含操作身份、阶段和结果而不是只有一段最终提示。typeOperationStageinit|insert|search|delete|manifest|rebuild|release;typeOperationOutcomesuccess|failure|uncertain;interfaceOperationRecord{operationId:string;stage:OperationStage;outcome:OperationOutcome;galleryRevision:number;itemId?:string;errorCode?:number;durationMs?:number;}同一次导入可以留下两条记录平台插入成功清单提交失败。它们共享 operationId但阶段不同。这样调查者就不会把“没有保存成功状态”误解为“服务从未插入”。结果未知时保留uncertain不要为了简化报表强行归类。日志写入本身也可能失败。记录模块需要限制大小、处理自己的写入错误并保证日志异常不会覆盖原始业务错误。它可以提供诊断线索却不能替代用于恢复的持久清单。普通运行日志不需要保存完整查询、相册 URI 或图片内容。第四篇的评测资料使用固定查询并单独保存实验条件。区分这两类记录既方便比较也避免交付时把个人照片和私人描述一起带走。页面继续只显示简洁原因与下一步操作。6. 检查应用规则最值得验证的往往是正常点击很难遇到的交界处。例如请求已经发出用户离开页面结果随后返回。为了稳定重现这个过程可以在测试替身中让搜索 Promise 等待测试主动完成。classSearchReplyControl{privatecomplete:((images:textSearchImage.ImageObject\[])void)|undefinedundefined;readonlyreply:PromisetextSearchImage.ImageObject\[]newPromisetextSearchImage.ImageObject\[]((resolve){this.completeresolve;});finish(images:textSearchImage.ImageObject\[]):void{if(this.completeundefined){return;}this.complete(images);this.completeundefined;}}让替身的 search 返回reply测试就能先发起查询再关闭页面最后调用finish。这比等待一个猜测的毫秒数更可靠。新的测试场景创建新的控制对象避免复用已经完成的 Promise。这一用例应同时检查两个结果旧查询不会向关闭后的页面发布内容新会话的初始化发生在旧调用和释放完成之后。再用拒绝 Promise 的分支检查异常提示及 finally防止旧任务把新页面的等待状态清除。另外几项检查围绕既定规则展开快速重复点击不产生并发调用删除记录成功、文件删除失败时保留 cleanup清单提交失败不显示完整成功相似度同分时保持原位置能力更新进入恢复流程。测试断言业务后果不依赖内部方法被调用多少层。图4控制异步返回的时机检查离开页面与请求完成之间的行为。7. 真机验收测试替身能检查应用规则不能回答平台在某台设备上的实际行为。完整文搜图链路仍需符合条件的真机Stage 模型以及官方支持的设备与地区范围。Core Vision Kit 不支持模拟器手机 Previewer 用于检查布局。验收记录写下实际机型、系统、SDK、DevEco 版本和必要环境条件。第一轮保留 sea01、sea02、hill01、coffee01、dog01使用三条固定查询lake01 仍属于扩展集。更换素材内容时同步更新版本与摘要。场景需要观察的行为首次进入文件准备、初始化、入库状态依次可解释已有图库重启读取清单并恢复不盲目重复插入重复导入与同名不同内容不重复确认未知结果不覆盖旧图片身份移除中断保留相册原图不重新加入待删除条目查询中离开再返回平台调用不重叠旧结果不回写空数组、调用失败、文件不可读页面给出不同原因与下一步能力更新恢复保留副本记录批次及未完成项相关性和耗时继续采用第四篇的口径保留原始返回与展示结果。没有发生的设备事件不用故障注入结果代替无法自然触发的错误可以单独记录应用分支如何验证。每项验收写清步骤、预期、实际结果和证据位置。未执行的项目标为待验证失败项保留复现条件。尤其是重复插入、删除幂等性和跨启动持久化只有明确依据才能成为后续实现的前提。图5三条固定查询贯穿整个系列便于在工程调整后沿相同路径检查结果。8. README交付材料应当让接手的人按顺序完成一次操作。先说明环境再说明构建与安装然后准备图库、执行查询最后介绍失败后的定位入口。只放 API 列表和效果图会把这些步骤重新留给读者猜测。README 记录具体工具版本及工程配置位置写明需要配置本机签名、选择设备和运行入口。构建命令必须与实际构建工具及模块一致若提供 HAP同时注明对应构建版本、签名和设备适用条件。开发签名产物不能被描述为所有设备都能安装。运行步骤保留两条路径首次进入需要准备样本并建立检索记录已有图库则读取清单并执行恢复判断。读者遇到按钮置灰时应能根据状态找到对应阶段而不是被要求反复重启。建议随工程保留固定样本清单、查询表、验收记录和已知限制。已知限制最好关联具体条件在哪种设备或操作下发生、目前如何处理、复查需要什么步骤。这样的记录能支持维护比一句“可能存在兼容性问题”更有用。交付前检查签名私钥、证书、个人相册副本及日志保留运行说明而不是私人凭据。图片处理范围和数据说明依据官方资料与应用实际行为编写不能从“不留存图片”进一步推出“完全离线”。图6README 给出环境、运行与验证入口让下一位开发者可以沿步骤开始。9. 总结第一篇从“一句话找照片”出发第二篇连接文件与搜索接口第三篇处理图库变化第四篇建立结果判断与交互规则。最后一篇把这些决定放回工程平台调用有入口持久数据有负责人会话有结束顺序修改有回归依据。维护者不需要从一段页面代码里猜出所有规则。他可以从一次用户操作找到对应模块从一条错误找到失败阶段再沿固定样本检查改动的影响。未来增加功能时也能看清应该修改哪个边界。最初的问题很小能不能用一句话找到照片围绕它我们逐步明确了图片由谁管理、请求如何执行、结果怎样判断以及失败以后如何继续。交付时留下这些决定下一位开发者才不必重新猜一遍。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑