HarmonyOS应用开发基础(下篇共上中下3篇)_第1页
HarmonyOS应用开发基础(下篇共上中下3篇)_第2页
HarmonyOS应用开发基础(下篇共上中下3篇)_第3页
HarmonyOS应用开发基础(下篇共上中下3篇)_第4页
HarmonyOS应用开发基础(下篇共上中下3篇)_第5页
已阅读5页,还剩80页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

项目7:数据存储在HarmonyOS应用开发中,数据持久化是保障用户体验与功能完整性的核心技术。本项目从文件存储基础出发,逐步深入应用数据管理的高效方案。通过文件基础服务(CoreFileKit)实现本地数据读写,掌握沙箱隔离与安全共享机制;结合ArkData(方舟数据管理)服务,学习用户首选项、关系型数据库等结构化存储技术,理解多场景下的数据同步与跨设备协作能力。导学目标知识目标掌握HarmonyOS文件存储核心机制,包括沙箱隔离、文件分类模型理解ArkData服务架构及其组件的适用场景熟悉CoreFileKit读写接口与ArkData标准化数据管理流程掌握用户首选项(Preferences)轻量级配置与关系型数据库增删改查操作能力目标能使用文件基础服务API实现本地数据读写与安全存储能基于用户首选项管理轻量级配置数据,并实现数据变更监听能设计并实现关系型数据库表结构,完成复杂数据的增删改查及事务管理能根据业务需求选择文件存储或数据库方案,完成数据迁移与性能优化素质目标培养独立分析问题、解决问题的能力,养成科学严谨的学习工作态度培养对数据安全与隐私保护的敏感意识,规范使用沙箱机制与加密策略任务1文件存储复杂应用不可避免地需要在本地存储一些必要数据,如设置信息、运行日志、帐号密码等,这些数据在应用退出后依然可以在设备上留存,以便后续使用。本任务将创建一个简易的登录界面,在完成UI设计的基础上,实现帐号注册和登录比对功能。ArkUI无法直接提供数据存储功能,这就需要HarmonyOS提供的文件基础服务来实现。7.1文件基础服务概述CoreFileKit(文件基础服务)为开发者提供一套访问和管理应用文件和用户文件的能力,帮助用户更高效地管理、查找和备份各类文件。按文件所有者不同,文件分为三大类:应用文件文件所有者为应用,包括应用安装文件、应用资源文件、应用缓存文件等。每个应用拥有独立的资源文件与缓存文件目录。用户文件文件所有者为登录到该终端设备的用户,包括用户私有的图片、视频、音频、文档等,分为内置存储与外置存储。系统文件与应用和用户无关的其他文件,包括公共库、设备文件、系统资源文件、配置文件等。不需要开发者进行文件管理。文件分类模型示意图图7-1展示了HarmonyOS文件分类模型。应用文件按用户(用户A/用户B)隔离,每个用户下各应用拥有独立的资源文件与缓存文件;用户文件存储在内置/外置存储中;系统文件位于最底层,由操作系统统一管理。7.1.2CoreFileKit使用场景与特性主要使用场景应用文件访问和文件分享应用数据备份恢复选择与保存用户文件跨设备的文件访问和分享能力两大核心特性①沙箱隔离:对于每个应用,系统会在内部存储空间映射出一个专属的"应用沙箱目录",它是"应用文件目录"与一部分系统文件所在目录组成的集合,避免数据受到恶意路径穿越访问。②应用分享:应用之间可以通过分享URI(UniformResourceIdentifier)或文件描述符FD(FileDescriptor)的方式进行文件共享,实现跨应用数据交互。7.2应用文件持久化应用文件指文件所有者为应用,包括应用安装文件、应用资源文件、应用缓存文件等。应用文件有如下核心特点:应用专属目录设备上应用所使用及存储的数据,以文件、键值对、数据库等形式保存在一个应用专属的目录内,称为应用文件目录。应用沙箱目录应用文件目录与一部分系统文件(应用运行必须使用的系统文件)所在的目录组成了一个集合,称为应用沙箱目录,代表应用可见的所有目录范围。只读系统文件系统文件及其目录对于应用是只读的。应用仅能保存文件到应用文件目录下,根据目录的使用规范和注意事项来选择将数据保存到不同的子目录中。7.2.1应用沙箱概述应用沙箱是一种以安全防护为目的的隔离机制,避免数据受到恶意路径穿越访问。在这种沙箱的保护机制下,应用可见的目录范围即为应用沙箱目录。图7-2展示了应用沙箱文件访问关系:应用进程可直接访问应用沙箱目录(含应用文件和少量系统文件),也可通过用户授权访问外部的用户文件,但无法直接访问外部系统文件。应用沙箱目录与沙箱路径图7-3展示了路径隔离过程:从系统进程视角经权限隔离到服务进程视角,再经挂载隔离到系统应用视角,最终到普通应用视角,可见文件和目录逐步减少。普通应用视角下看到的路径称为应用沙箱路径,与实际物理路径并非1:1映射关系,沙箱路径总是少于系统进程视角可见的物理路径。应用文件目录结构图7-4展示了应用文件目录的七级结构:一级

data/(应用文件根目录)→二级

storage/(持久化文件目录)→三级

el1/~el4/(文件加密类型,加密等级越高越严格,一般应将数据存放在el2加密目录下)→四/五级通过ApplicationContext获取files、cache、preferences、temp等目录路径→六/七级HAP级别应用文件路径(随HAP卸载而删除)。应用文件路径说明(表7-1)目录名Context属性名类型说明bundlebundleCodeDir安装文件路径应用安装后HAP资源包所在目录;随应用卸载而清理。不能拼接路径访问资源文件,需使用资源管理接口。baseNA本设备文件路径应用在本设备上存放持久化数据的目录,子目录包含files/、cache/、temp/和haps/;随应用卸载而清理。databasedatabaseDir数据库路径应用在el2加密条件下存放通过分布式数据库服务操作的文件目录;仅用于保存私有数据库数据。distributedfilesdistributedFilesDir分布式文件路径应用在el2加密条件下存放分布式文件的目录,可分布式跨设备直接访问;适合多设备共享/备份/协助文件。filesfilesDir应用通用文件路径通用的存放默认长期保存的文件路径;可保存用户持久性文件、图片、媒体文件及日志文件等。cachecacheDir应用缓存文件路径用于缓存下载的文件或可重新生成的缓存文件;超过配额或系统空间不足时自动清理,不要存储重要数据。preferencespreferencesDir应用首选项文件路径通过数据库API存储配置类或首选项的目录;仅适用于存储少量数据。temptempDir应用临时文件路径仅在应用运行期间产生和需要的文件,应用退出后即清理;适合存储数据库缓存、临时日志、下载安装包等。沙箱路径与物理路径对应关系(表7-2)应用沙箱路径物理路径/data/storage/el1/bundle应用安装包目录:/data/app/el1/bundle/public//data/storage/el1/base应用el1级别加密数据目录:非独立沙箱运行的应用:/data/app/el1/<USERID>/base/<PACKAGENAME>;以独立沙箱运行的Extension应用:/data/app/el1/<USERID>/base/+extension-<EXTENSIONPATH>+<PACKAGENAME>/data/storage/el2/base应用el2级别加密数据目录:非独立沙箱:/data/app/el2/<USERID>/base/<PACKAGENAME>;独立沙箱Extension:/data/app/el2/<USERID>/base/+extension-+<PACKAGENAME>/data/storage/el1/database应用el1级别加密数据库目录:非独立沙箱:/data/app/el1/<USERID>/database/<PACKAGENAME>;独立沙箱Extension:/data/app/el1/<USERID>/database/+extension-+<PACKAGENAME>/data/storage/el2/database应用el2级别加密数据库目录:非独立沙箱:/data/app/el2/<USERID>/database/<PACKAGENAME>;独立沙箱Extension:/data/app/el2/<USERID>/database/+extension-+<PACKAGENAME>/data/storage/el2/distributedfiles/mnt/hmdfs/<USERID>/account/merge_view/data/<PACKAGENAME>7.2.2应用文件访问接口(表7-3)开发者通过基础文件操作接口(ohos.file.fs)实现应用文件访问能力。支持同步的接口在命名上需额外加上Sync,例如同步打开文件为openSync,同步读取文件为readSync。接口名功能接口类型同步异步access检查文件是否存在方法√√close关闭文件方法√√copyFile复制文件方法√√listFile列出文件夹下所有文件名方法√√mkdir创建目录方法√√open打开文件方法√√read从文件读取数据方法√√write将数据写入文件方法√√unlink删除单个文件方法√√stat获取文件详细属性信息方法√√rename重命名文件或文件夹方法√√File.fd获取文件描述符属性--OpenMode设置文件打开标签属性--应用文件访问步骤:导入模块与获取路径01导入模块导入文件基础服务对象fileIo,并重命名为fs,后续通过fs.接口名()完成调用。import{fileIoasfs}from'@kit.CoreFileKit';02获取应用沙箱路径对文件/目录进行操作前,需先获取其应用沙箱路径。在UIAbility内通过this.context获取上下文,或通过getContext(this)获取:letcontext=getContext(this)ascommon.UIAbilityContext;letfilesDir=context.filesDir;03新建/打开文件使用openSync接口打开或新建文件。第一个参数为沙箱路径,第二个可选参数mode为打开选项(READ_ONLY/WRITE_ONLY/READ_WRITE),可通过"|"叠加额外选项(CREATE/TRUNC/APPEND等)。letfile=fs.openSync(filesDir+'/'+fileName,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);应用文件访问步骤:读写与关闭01写数据到文件(writeSync)第一个参数为文件描述符,第二个参数为待写入数据(ArrayBuffer或string),第三个可选参数支持offset(写入位置)、length(写入长度)、encoding(编码方式,默认utf-8)。返回值为实际写入的字节长度。letdata='writethisstringtofile';fs.writeSync(file.fd,data);02从文件读数据(readSync)第一个参数为文件描述符,第二个参数为保存读取数据的缓冲区(ArrayBuffer),第三个可选参数支持offset(读取位置)、length(读取长度)。返回值为实际读取的字节长度。letarrayBuffer=newArrayBuffer(1024);letreadLen=fs.readSync(file.fd,arrayBuffer);letbufferRd:string=buffer.from(arrayBuffer,0,readLen);03关闭文件(closeSync)已打开的文件不再使用时,必须通过closeSync接口关闭该文件,以避免潜在的访问异常。关闭后file对象或文件描述符不再具备实际意义,不可再用于读写等操作。fs.closeSync(file.fd);任务实施任务1实施思路本任务创建一个简易登录界面,通过文件基础服务实现帐号注册与登录比对功能。UI设计设计登录页,包含帐号、密码、登录、注册按钮。注册功能使用writeSync将帐号和密码写入应用文件。登录功能用readSync读取文件并与输入信息比对。以EmptyAbility模板、SDK版本13、设备类型为Phone创建项目,将Project视图切换为Ohos视图,编辑入口组件所在页面entry/ets/pages/Index.ets完成功能。任务1过程代码:注册功能(文件7-1)步骤2:通过文件基础服务完成注册功能,涉及文件写入操作(Index_step2.ets):import{fileIoasfs}from'@kit.CoreFileKit';import{common}from'@kit.AbilityKit';letcontext=getContext(this)ascommon.UIAbilityContext;letfilesDir=context.filesDir;constFILE_NAME_ACCOUNT='account.txt';constFILE_NAME_PASSWORD='password.txt';writeFile(fileName:string,data:string){letfile=fs.openSync(filesDir+'/'+fileName,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);fs.truncateSync(file.fd,0);//更新数据前清空文件内容fs.writeSync(file.fd,data);fs.closeSync(file.fd);}registerAccount():void{if(this.account===null||this.password===null||this.account===''||this.password===''){AlertDialog.show({title:'提示',message:'请正确输入帐号和密码'});return;}this.writeFile(FILE_NAME_ACCOUNT,this.account);this.writeFile(FILE_NAME_PASSWORD,this.password);}任务1过程代码:登录功能(文件7-2)步骤3:通过文件基础服务实现登录功能,涉及文件读取(Index.ets):readFile(fileName:string):string{letarrayBuffer=newArrayBuffer(1024);letfile=fs.openSync(filesDir+'/'+fileName,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);letreadLen=fs.readSync(file.fd,arrayBuffer);letbufferRd=buffer.from(arrayBuffer,0,readLen);fs.closeSync(file.fd);returnbufferRd.toString();}checkAccount():void{if(this.account==null||this.password==null||this.account==''||this.password==''){AlertDialog.show({title:'提示',message:'请正确输入帐号和密码'});return;}letaccountRd=this.readFile(FILE_NAME_ACCOUNT);letpasswordRd=this.readFile(FILE_NAME_PASSWORD);if(accountRd===this.account&&passwordRd===this.password){AlertDialog.show({title:'登录成功',message:'欢迎登录:'+accountRd});}else{AlertDialog.show({title:'登录失败',message:'账号:'+accountRd+'密码:'+passwordRd});}}任务1运行结果图7-5:用户注册帐号时,可在对应的应用文件目录写入帐号和密码文件,文件可通过IDE的DeviceFileBrowser进行查看。图7-6:帐号注册后,输入正确帐号和密码,点击"登录"按钮后,可以正常完成帐号核对,弹出登录成功提示。拓展提升与思考感悟拓展提升本任务实现了登录界面的注册与登录功能,但只实现了一个帐号的存储。读者可以通过阅读文件基础服务接口,自行实现更为复杂的多帐号注册与登录匹配功能,进一步提升对CoreFileKit的掌握程度。思考感悟本项目通过实现登录功能,深入探讨了HarmonyOS文件存储的核心机制。文件基础服务(CoreFileKit)为应用数据持久化提供了安全高效的解决方案,其沙箱隔离机制为每个应用划定独立空间,保障数据互不侵犯。人与人之间也需要这样的边界感——尊重他人隐私,守住自己底线,社会才能和谐安宁。任务2应用数据持久化前一节任务中,在管理大量帐号的场景下,文件基础操作在查询、写入和管理方面效率较低。文件基础服务提供的文件操作可以完成数据的存储,但在数据管理效率、结构化数据管理的灵活性以及扩展性来说,都无法直接胜任要求。本任务将对上一节登录页面进行改良,采用应用数据持久化技术进行实现。针对应用数据持久化技术,HarmonyOS系统提供了方舟数据管理服务(ArkData)。7.3方舟数据管理(ArkData)简介ArkData(方舟数据管理)为开发者提供数据存储、数据管理和数据同步能力。例如,联系人应用数据可以保存到数据库中,ArkData提供数据库的安全、可靠及共享访问等管理机制,也支持与手表同步联系人信息。标准化数据定义提供HarmonyOS跨应用、跨设备的统一数据类型标准,包含标准化数据类型和标准化数据结构。数据存储提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库三种形态。数据管理提供高效的数据管理能力,包括权限管理、数据备份恢复、数据共享框架等。数据同步提供跨设备数据同步能力,如分布式对象支持内存对象跨设备共享,分布式数据库支持跨设备数据库访问。应用创建的数据库都保存到应用沙箱,当应用卸载时,数据库也会自动删除。路径关键词为database。7.3.2ArkData运作机制架构图图7-7展示了ArkData三层架构:JSAPI层提供标准接口(Preferences、KV-Store、RelationalStore、DataObject、DataShare、UDMF);Frameworks&Systemservice层负责实现各部件数据存储与同步功能,底部由数据管理服务(DatamgrService)统一协调;OS层依赖sqlite3、文件系统、安全子系统等底层组件。ArkData各模块功能详解用户首选项(Preferences)提供轻量级配置数据的持久化能力,支持订阅数据变化通知。不支持分布式同步,常用于保存应用配置信息、用户偏好设置等。键值型数据管理(KV-Store)提供键值型数据库的读写、加密、手动备份及订阅通知能力。需要分布式能力时,KV-Store将同步请求发送给DatamgrService完成跨设备数据同步。关系型数据管理(RelationalStore)提供关系型数据库的增删改查、加密、手动备份及订阅通知能力。需要分布式能力时,RelationalStore将同步请求发送给DatamgrService完成跨设备数据同步。分布式数据对象(DataObject)独立提供对象型结构数据的分布式能力。应用需要重启后仍获取之前的对象数据时,使用DatamgrService的对象持久化能力做暂时保存。跨应用数据管理(DataShare)提供数据提供者provider、数据消费者consumer以及同设备跨应用数据交互的增删改查及订阅通知能力。不与任何数据库绑定,可对接关系型或键值型数据库。统一数据管理框架(UDMF)提供数据跨应用、跨设备交互标准,定义了跨应用、跨设备数据交互过程中的数据语言,提升数据交互效率。7.4应用数据持久化三种形态对比HarmonyOS标准系统支持三种典型的存储数据形态,开发者可根据业务需求选择合适的方案:7.4.1用户首选项(Preferences)场景介绍与运作机制用户首选项为应用提供Key-Value键值型数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。Preferences会将数据缓存在内存中,读取时能快速从内存获取,可通过flush接口将内存中的数据持久化至文件。适用场景:应用保存用户的个性化设置(字体大小、是否开启夜间模式等)。约束限制不保证进程并发安全,不支持多进程场景Key为string类型,非空且长度不超过1024字节Value为string类型时使用UTF-8编码,不为空时长度不超过16MB非UTF-8格式字符串请使用Uint8Array类型存储,否则会造成持久化文件格式错误调用removePreferencesFromCache()或deletePreferences()后,订阅的数据变更会主动取消,重新调用getPreferences()后需再次订阅建议存储数据不超过一万条,否则内存开销较大用户首选项运作机制图图7-8展示了用户首选项运作机制:用户程序通过ArkTS接口调用用户首选项读写对应的数据文件。每个文件唯一对应到一个Preferences实例,系统通过静态容器将该实例存储在内存中,直到主动从内存中移除该实例或者删除该文件。应用首选项的持久化文件保存在应用沙箱内部,可以通过context获取其路径。用户首选项常用接口说明(表7-1)接口名称描述getPreferencesSync(context,options)获取Preferences实例。该接口存在异步版本。putSync(key,value)将数据写入Preferences实例,可通过flush将实例持久化。当对应键已存在时会覆盖其值。该接口存在异步版本。hasSync(key)检查Preferences实例是否包含名为给定Key的存储键值对。给定的Key值不能为空。该接口存在异步版本。getSync(key,defValue)获取键对应的值,如果值为null或者非默认值类型,返回默认数据defValue。该接口存在异步版本。deleteSync(key)从Preferences实例中删除名为给定Key的存储键值对。该接口存在异步版本。flush(callback)将当前Preferences实例的数据异步存储到用户首选项持久化文件中。on(type:'change',callback)订阅数据变更,订阅的数据发生变更后,在执行flush()方法后触发callback回调。off(type:'change',callback?)取消订阅数据变更。deletePreferences(context,options,callback)从内存中移除指定的Preferences实例。若有对应的持久化文件,则同时删除其持久化文件。用户首选项开发步骤01①导入模块import{preferences}from'@kit.ArkData';02②获取Preferences实例letdataPreferences:preferences.Preferences|null=null;letoptions:preferences.Options={name:'myStore'};dataPreferences=preferences.getPreferencesSync(context,options);03③写入数据(putSync)if(dataPreferences.hasSync('startup')){('Thekeystartupiscontained.');}else{dataPreferences.putSync('startup','auto');//特殊字符需转为Uint8Array存储letuInt8Array1=newutil.TextEncoder().encodeInto("~!@#%&.*()——+?");dataPreferences.putSync('uInt8',uInt8Array1);}04④读取数据(getSync)letval=dataPreferences.getSync('startup','default');//获取Uint8Array类型时需转换为字符串letuInt8Array2=dataPreferences.getSync('uInt8',newUint8Array(0));lettextDecoder=util.TextDecoder.create('utf-8');val=textDecoder.decodeToString(uInt8Array2asUint8Array);05⑤删除数据/持久化/订阅变更/删除文件删除键值对:dataPreferences.deleteSync('startup');数据持久化:调用flush()将缓存写入文件;订阅变更:调用on()传入回调方法;删除指定文件:调用deletePreferences()从内存移除实例并删除持久化文件。7.4.2关系型数据库(RelationalStore)概述与运作机制关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景,例如班级学生信息(姓名、学号、各科成绩)或公司雇员信息(姓名、工号、职位)。图7-9:应用通过关系型数据库框架(kits+Framework)访问底层SQLite组件,支持事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。约束限制系统默认日志方式为WAL(WriteAheadLog)模式,默认落盘方式为FULL模式数据库中有4个读连接和1个写连接;无空闲读连接时,写连接可作为读连接使用同一时间只能支持一个写操作,以保证数据准确性应用卸载后,相关数据库文件及临时文件会被自动清除ArkTS支持的基本数据类型:number、string、二进制类型数据、boolean建议一条数据不超过2MB,超出则插入成功但读取失败关系型数据库操作主要接口(表7-2)接口名描述getRdbStore(context,config,callback)获得一个RdbStore,操作关系型数据库。用户可根据需求配置RdbStore的参数,然后通过RdbStore调用相关接口执行数据操作。executeSql(sql,bindArgs,callback)执行包含指定参数但不返回值的SQL语句,常用于建表、建库等DDL操作。insert(table,values,callback)向目标表中插入一行数据。操作成功返回行ID,否则返回-1。update(values,predicates,callback)根据predicates的指定实例对象更新数据库中的数据,返回受影响的行数。delete(predicates,callback)根据predicates的指定实例对象从数据库中删除数据,返回受影响的行数。query(predicates,columns,callback)根据指定条件查询数据库中的数据,返回ResultSet结果集对象。columns为空则查询所有列。deleteRdbStore(context,name,callback)删除数据库及数据库相关文件。关系型数据库开发步骤:导入与获取RdbStore01①导入模块import{relationalStore}from'@kit.ArkData';02②获取RdbStore(建库建表)配置参数包括数据库文件名name、安全级别securityLevel、是否加密encrypt、自定义路径customDir。数据库默认版本为0,通过判断版本防止重复建表:constSTORE_CONFIG:relationalStore.StoreConfig={name:'RdbTest.db',securityLevel:relationalStore.SecurityLevel.S3,encrypt:false,customDir:'customDir/subCustomDir',};constSQL_CREATE_TABLE='CREATETABLEIFNOTEXISTSEMPLOYEE'+'(IDINTEGERPRIMARYKEYAUTOINCREMENT,'+'NAMETEXTNOTNULL,AGEINTEGER,'+'SALARYREAL,CODESBLOB,IDENTITYUNLIMITEDINT)';rdb=awaitrelationalStore.getRdbStore(context,STORE_CONFIG);if(rdb.version===0){rdb.executeSql(SQL_CREATE_TABLE);rdb.version=1;}关系型数据库开发步骤:插入与修改数据插入数据:调用insert()接口,第一个参数为目标表名,第二个参数为ValuesBucket键值对,第三个参数为callback回调(成功返回行ID,否则返回-1):constvalueBucket:relationalStore.ValuesBucket={'NAME':'Lisa','AGE':18,'SALARY':100.5,'CODES':newUint8Array([1,2,3,4,5]),'IDENTITY':BigInt('15822401018187971961171'),};rdb.insert('EMPLOYEE',valueBucket,(err,rowId)=>{if(err){return;}//插入成功,rowId为新行ID});修改数据:调用update(),通过RdbPredicates指定更新条件;删除数据:调用delete(),同样通过RdbPredicates指定删除条件:letpredicates=newrelationalStore.RdbPredicates('EMPLOYEE');predicates.equalTo('NAME','Lisa');rdb.update(valueBucket4,predicates,(err,rows)=>{...});predicates.equalTo('NAME','Lisa');rdb.delete(predicates,(err,rows)=>{(`Deleterows:${rows}`);});关系型数据库开发步骤:查询与删除数据库查询数据:调用query()方法,返回ResultSet结果集。ResultSet是一个数据集的游标,默认指向第1个记录,有效数据从0开始,使用完毕后需调用close()释放内存:letpredicates2=newrelationalStore.RdbPredicates('EMPLOYEE');predicates2.equalTo('NAME','Rose');rdb.query(predicates2,['ID','NAME','AGE','SALARY','IDENTITY'],(err,resultSet)=>{if(err){return;}while(resultSet.goToNextRow()){constid=resultSet.getLong(resultSet.getColumnIndex('ID'));constname=resultSet.getString(resultSet.getColumnIndex('NAME'));constage=resultSet.getLong(resultSet.getColumnIndex('AGE'));constsalary=resultSet.getDouble(resultSet.getColumnIndex('SALARY'));(`id=${id},name=${name},age=${age},salary=${salary}`);}resultSet.close();//释放数据集内存});删除数据库:调用deleteRdbStore()方法删除数据库及相关文件:rdb.deleteRdbStore(context,'RdbTest.db',(err)=>{if(err){return;}('SucceededindeletingRdbStore.');});任务实施任务2实施思路本任务对上一节登录页面进行改良,采用关系型数据库实现帐号注册与登录功能,支持多帐号存储。登录函数注册函数UI设计以EmptyAbility模板、SDK版本13、设备类型为Phone创建项目,将Project视图切换为Ohos视图,编辑entry/ets/pages/Index.ets完成功能。任务2过程代码:注册功能(文件7-3)步骤2:通过ArkData完成注册功能,涉及关系型数据库查询与写入(Index_step2.ets):constFILE_NAME_ACCOUNT='RdbAccount.db';constTABLE_NAME_ACCOUNT='EMPLOYEE';constCOLUMN_NAME_ACCOUNT='ACCOUNT';constCOLUMN_NAME_PASSWORD='PASSWORD';letrdb:relationalStore.RdbStore;asyncgetDb(){constSTORE_CONFIG:relationalStore.StoreConfig={name:FILE_NAME_ACCOUNT,securityLevel:relationalStore.SecurityLevel.S1,encrypt:false,};constSQL_CREATE_TABLE='CREATETABLEIFNOTEXISTS'+TABLE_NAME_ACCOUNT+'(IDINTEGERPRIMARYKEYAUTOINCREMENT,'+'ACCOUNTTEXTNOTNULL,PASSWORDTEXTNOTNULL)';rdb=awaitrelationalStore.getRdbStore(context,STORE_CONFIG);if(rdb.version===0){rdb.executeSql(SQL_CREATE_TABLE);rdb.version=1;}}registerAccount():void{//查询数据库,如果帐号存在则不做处理;否则插入数据库letpredicates=newrelationalStore.RdbPredicates(TABLE_NAME_ACCOUNT);predicates.equalTo(COLUMN_NAME_ACCOUNT,this.account);rdb.query(predicates,['ACCOUNT'],(err,resultSet)=>{if(err){return;}if(resultSet.rowCount>0){return;}//帐号已存在constvalue:relationalStore.ValuesBucket={ACCOUNT:this.account,PASSWORD:this.password};rdb.insert(TABLE_NAME_ACCOUNT,value,(err,rowId)=>{...});});}任务2过程代码:登录功能(文件7-4)步骤3:通过ArkData实现登录功能,涉及关系型数据库查询(Index.ets):checkAccount():void{if(this.account==null||this.password==null||this.account==''||this.password==''){AlertDialog.show({title:'提示',message:'请正确输入帐号和密码'});return;}letpredicates=newrelationalStore.RdbPredicates(TABLE_NAME_ACCOUNT);predicates.equalTo(COLUMN_NAME_ACCOUNT,this.account);predicates.equalTo(COLUMN_NAME_PASSWORD,this.password);rdb.query(predicates,['ACCOUNT','PASSWORD'],(err,resultSet)=>{if(err){return;}if(resultSet.rowCount>0){resultSet.goToNextRow();letaccountRd=resultSet.getString(resultSet.getColumnIndex(COLUMN_NAME_ACCOUNT));letpasswordRd=resultSet.getString(resultSet.getColumnIndex(COLUMN_NAME_PASSWORD));if(accountRd===this.account&&passwordRd===this.password){AlertDialog.show({title:'登录成功',message:'欢迎登录:'+accountRd});}else{AlertDialog.show({title:'登录失败',message:'账号:'+accountRd+'密码:'+passwordRd});}}else{AlertDialog.show({title:'登录失败',message:'帐号不存在'});}});}任务2运行结果图7-10:用户注册帐号时,可在对应的应用文件目录写入帐号和密码文件(RdbAccount.db、RdbAccount.db-shm、RdbAccount.db-wal),文件可通过IDE的DeviceFileBrowser进行查看。与上一任务不同,由于项目采用关系型数据库存储,所以可以注册多个帐号。任务2拓展提升与思考感悟拓展提升本任务实现了登录界面的注册与登录功能,但没有实现帐户密码的修改功能。读者可以自行丰富代码,调用update()接口完成密码修改功能,进一步掌握关系型数据库的增删改查操作。思考感悟本任务通过登录功能升级,系统梳理了数据持久化的核心方案:用户首选项轻量高效,关系型数据库支撑复杂业务。实践中我们掌握了建表、增删改查等操作。数据管理讲求规范有序,社会运转同样需要规则——井井有条才能高效运行,按章办事方能行稳致远。习题与实训课后习题1应用沙箱的意义为什么要有应用沙箱?它存在的意义是什么?2用户首选项适用场景用户首选项的数据存储比较适合什么应用场景?3关系型数据库适用场景关系型数据库比较适合什么应用场景?实训目的掌握文件存储的使用方法掌握用户首选项的使用方法熟悉关系型数据库的使用方法实训内容构建一个记事本应用App,并进行测试。要求:有登录页面和文字书写页面登录页面可通过帐号和密码完成登录,并具有新帐号注册功能文字书写页面有记事列表,点击后可打开文本编辑,或通过新建记事来打开文本编辑,文本编辑可进行保存项目7知识总结项目8:卡片及元服务元服务是HarmonyOS面向未来的免安装服务形式,是原生智能的最佳载体,具备精准服务触达和原生自然体验。卡片作为应用入口之一,能为用户带来更好的元服务体验。本项目详细讲解卡片及元服务开发知识。导学:学习目标总览知识目标理解服务卡片概念与使用场景掌握卡片运行机制及开发步骤理解元服务概念与使用场景了解AppGalleryConnect平台了解卡片与元服务之间的关系掌握元服务开发流程能力目标能为传统应用及元服务应用创建卡片能运用卡片事件刷新卡片能应用ArkUI设计卡片页面能在AppGalleryConnect中创建元服务应用能在DevEcoStudio中创建元服务工程能应用元服务API开发元服务应用素质目标培养独立分析问题、解决问题的能力培养科学严谨的学习工作态度养成良好的职业素养任务1音乐播放卡片设计任务描述:实现一个音乐播放应用,为该应用创建音乐播放卡片。在卡片上点击播放按钮,应用能在后台播放音乐,按钮状态在"播放"与"暂停"之间切换;点击卡片按钮之外的区域能拉起应用播放页面;播放页面的播放按钮状态必须与卡片上的播放按钮状态保持同步;当为应用添加卡片时,卡片上的播放按钮状态必须与应用播放页面的播放按钮状态一致。8.1卡片开发基础桌面卡片不仅可作为传统应用的入口,也可作为元服务应用入口,使用户更为快捷、方便地拉起应用。卡片对传统应用及元服务应用而言不是必需,但能有效提升用户的使用体验。什么是卡片服务卡片类似桌面图标,提供界面展示形式,两者均能拉起应用。但图标内容不支持交互,而卡片则可以,如实现卡片界面刷新等。卡片还可将应用的重要信息或操作前置,达到服务直达、减少跳转层级的体验效果,并提供定时、定点等多种刷新机制,实现卡片永久在线。卡片分类(渲染层面)动态卡片:支持动效能力,可频繁刷新。静态卡片:使用最后一帧渲染数据,释放所有运行资源以节省内存,不支持动效,不能频繁刷新(会增加系统开销)。卡片分类(存在时间)临时卡片:短期存在,在特定事件触发后显示,完成展示目的后自动消失。可通过onCastToNormalForm()接口转为常态卡片,但目前桌面不使用临时卡片,暂无场景触发该接口。常态卡片:长期存在于桌面。服务直达以卡片形式呈现核心信息,简化交互流程,无须频繁跳转层级。永久在线提供定时、代理等多种卡片刷新机制,实现卡片永久在线发送消息。受限管控卡片支持的组件、事件、动画、数据管理、状态管理和API均进行了限制,保障性能、功耗及安全可靠。8.1.2卡片运行机制图8-1ArkTS卡片运行机制卡片运行机制:四大角色卡片使用方显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。当前仅系统应用(如桌面)可作为卡片使用方。卡片提供方提供卡片显示内容的应用,控制卡片的显示内容、控件布局以及控件点击事件。卡片管理服务管理系统中所添加卡片的常驻代理服务,提供formProvider接口能力,同时提供卡片对象的管理与使用以及卡片周期性刷新等能力。卡片渲染服务管理卡片渲染实例,渲染实例与卡片使用方上的卡片组件一一绑定。运行卡片页面代码widgets.abc进行渲染,并将渲染后的数据发送至对应的卡片组件。卡片采用专门的卡片渲染服务执行页面代码,由卡片管理服务监管。属于同一应用提供方的渲染实例在同一ArkTS虚拟机环境中运行,不同应用提供方的渲染实例在各自独立的ArkTS虚拟机环境中运行,实现资源与状态的有效隔离。应用的主进程持有UIAbility,卡片进程持有FormExtensionAbility,两者相互独立。8.1.3卡片生命周期回调FormExtensionAbility作为卡片扩展模块,提供卡片创建、销毁、刷新等生命周期回调。需要注意的是,FormExtensionAbility实例创建后5秒内无操作将会被清理,可以用message事件机制重新拉起。onAddForm(want)使用方创建卡片时触发,返回卡片页面绑定的数据。参数Want包含卡片ID、卡片名称、卡片样式等,这些信息必须作为持久数据管理,以便后续更新和删除卡片。onCastToNormalForm(formId)卡片提供方接收临时卡片转常态卡片的通知。onUpdateForm(formId)卡片定时更新/定点更新/卡片使用方主动请求更新卡片时触发。获取最新数据后调用formProvider的updateForm()接口刷新卡片数据。onFormEvent(formId,message)卡片提供方接收处理卡片事件的通知。onRemoveForm(formId)卡片提供方接收销毁卡片的通知。onAcquireFormState(want)卡片提供方接收查询卡片状态通知,默认返回卡片初始状态(该方法可以选择性重写)。8.1.4卡片开发模块及配置核心开发模块FormExtensionAbility卡片扩展模块,提供卡片创建、销毁、刷新等生命周期回调接口,运行在单独进程中,与UIAbility分离。formProvider通过updateForm()、setFormNextRefreshTime()及getFormsInfo()接口实现更新卡片、设置下次更新时间、获取卡片信息。formBindingData提供卡片页面绑定数据功能。createFormBindingData()接口创建FormBindingData对象,数据保存在卡片持有的LocalStorage中,通常与@LocalStorageProp修饰的状态量绑定。postCardAction/FormLinkpostCardAction用于动态卡片内部与提供方应用间的交互;FormLink用于静态卡片交互,仅用于卡片页面。form_config.json关键配置项name:卡片名称,最大127字节displayName:展示名称,1~30字节src:卡片UI代码文件路径uiSyntax:卡片类型(arkts/html)colorMode:主题样式(auto/dark/light)isDefault:是否为默认卡片updateEnabled:是否支持周期性刷新scheduledUpdateTime:定点刷新时刻(24小时制)updateDuration:定时刷新周期(单位:30分钟)defaultDimension:默认外观规格(如2*2)isDynamic:是否为动态卡片dataProxyEnabled:是否支持代理刷新8.1.5为应用添加卡片按压应用图标,弹出菜单,选择"卡片"选项,点击"添加至桌面"按钮,即可完成卡片添加。图8-2添加卡片:长按应用图标→选择"卡片"→点击"添加至桌面"8.2卡片事件概述为降低鸿蒙系统能耗,卡片进程的存活时间被设定了限制。卡片并非应用的组成部分,而是由系统桌面应用管理的独立服务,仅能通过特定接口进行数据交换和页面管理。每张卡片持有独立的LocalStorage,与应用的LocalStorage隔离,UIAbility与FormExtensionAbility无法直接访问卡片的LocalStorage。因此,鸿蒙系统设计了一套事件机制以触发相关应用,重新与卡片进行数据通信。router事件拉起实体应用到前台,也可通过数据交互刷新卡片内容。在UIAbility的onCreate()或onNewWant()中获取数据。call事件将销毁的应用拉起后到后台,需具备后台运行权限(ohos.permission.KEEP_BACKGROUND_RUNNING)。通过RPC方式传输数据,目前在元服务中不支持。message事件只能与FormExtensionAbility进行通信,如果FormExtensionAbility被清理,可再次拉起以刷新卡片内容。在onFormEvent()回调中获取数据。卡片事件图示(图8-3)图8-3ArkTS卡片事件:router/call事件触发UIAbility;message事件触发FormExtensionAbility的onFormEvent()回调。8.2.2postCardAction()接口与FormLink组件postCardAction()接口与FormLink组件仅用于卡片中,以发送卡片事件与实体应用进行数据交互。前者用于动态卡片,后者用于静态卡片。postCardAction()接口声明postCardAction(component:Object,action:Object):voidaction参数说明action(必填):router/message/callbundleName:router/call时跳转的包名moduleName:router/call时跳转的模块名abilityName:router/call时跳转的UIAbility名uri:router时跳转的统一资源标识符params:携带的额外参数(JSON键值对);call类型时需填入method参数示例:router事件(例8-1)Button('拉起应用至前台').onClick(()=>{postCardAction(this,{action:'router',abilityName:'EntryAbility',params:{message:'Hi'}});});示例:message事件(例8-3)Button('拉起FormExtensionAbility').onClick(()=>{postCardAction(this,{action:'message',params:{message:'Hi'}});});FormLink组件(例8-4)FormLink({action:'router',abilityName:'EntryAbility',params:{message:'Hi'}}){Button('拉起应用至前台')}8.3卡片刷新卡片刷新指卡片页界面内容(如文本、图片等)改变。ArkTS卡片框架提供了formProvider模块的updateForm()和requestForm()接口主动触发卡片的页面刷新,通过卡片持有的LocalStorage确认需要刷新的卡片数据。updateForm()仅提供方调用,只允许刷新自己的卡片;requestForm()仅使用方调用,只允许刷新添加到当前使用方的卡片。1updateForm()接口将数据发送给卡片页面以刷新卡片。参数formId为接收数据的卡片标识;formBindingData为发送的数据,保存于卡片持有的LocalStorage中,常用@LocalStorageProp读取。2createFormBindingData()接口创建FormBindingData对象,封装发送给卡片页面的数据。参数obj通常用Record<key,value>泛型封装,key名称必须与卡片页面中@LocalStorageProp的参数名一致。3getFormsInfo()接口获取设备上当前应用程序的卡片信息。可传入过滤器FormInfoFilter(仅有moduleName属性),返回符合条件的卡片配置信息数组。4setFormNextRefreshTime()接口设置卡片的下一次更新时间。参数formId为卡片标识;minute指定多久之后更新,单位为分钟,值大于或等于5。8.3.2通过卡片事件刷新卡片Router事件Message事件Call事件router事件刷新流程通过postCardAction()触发router事件拉起应用至前台,在onCreate()或onNewWant()中准备数据,获取formId,调用updateForm()发送数据卡片LocalStorage接收数据,用@LocalStorageProp读取并刷新卡片message事件刷新流程通过postCardAction()触发message事件拉起FormExtensionAbility,在onFormEvent()中准备数据,调用updateForm()发送数据卡片LocalStorage接收数据,用@LocalStorageProp读取并刷新卡片call事件刷新流程卡片组件获取卡片formId(通过onAddForm()获取后用updateForm()发送给卡片)通过postCardAction()携带method、formId触发call事件拉起应用至后台,UIAbility的onCreate()中用Callee对象的on()接口订阅回调,在onDestroy()中取消订阅回调中获取formId及数据,调用updateForm()刷新卡片call事件需要应用具备后台运行权限:ohos.permission.KEEP_BACKGROUND_RUNNING,需在module.json5中添加权限声明。卡片刷新效果(图8-4)图8-4卡片刷新(例8-5):点击卡片上的"播放/暂停"按钮,使之来回切换。实例源码参看CardRefresh工程。左图为播放状态,右图为暂停状态。任务实施音乐播放卡片:实施思路01后台播控卡片用call事件拉起实体应用于后台,实现音乐的后台播控。02前台播控卡片用router事件拉起实体应用的播控页面,实现音乐的前台播控,并通过setWindowSystemBarEnable()实现沉浸式窗口。03新卡片状态同步添加卡片时,通过onAddForm()获取formId,传给卡片状态量(用@Watch装饰),在响应函数中触发call事件携带formId,UIAbility订阅回调获取formId及当前播放状态,调用formProvider.updateForm()刷新卡片。04播控按钮同步实体应用播控音乐时,UIAbility获取当前播放状态,通过formProvider.updateForm()刷新卡片,使卡片与应用页面的播控按钮状态保持一致。05MusicService封装将音乐播控逻辑封装为MusicService类。MusicService声明回调函数但不实现,其实现交给EntryAbility;EntryAbility实现回调函数后注入MusicService,MusicService在需要时调用。通过这种方式实现两个类对象之间的数据交互。任务代码:EntryAbility.ets(文件8-1)UIAbility组件,程序入口类。核心逻辑:注册call事件回调、初始化音乐服务、刷新卡片数据。exportdefaultclassEntryAbilityextendsUIAbility{//播放/暂停回调(call事件触发)playOrPauseCallBack=(data:rpc.MessageSequence)=>{letparams=JSON.parse(data.readString());if(params.status==='PAUSE')MusicService.getInstance().play();elseif(params.status==='PLAY')MusicService.getInstance().pause();returnnull;};//添加卡片时初始化卡片播放按钮状态initCardCallBack=(data:rpc.MessageSequence)=>{letparams=JSON.parse(data.readString());if(params.formId){MusicService.getInstance().setPlayStateCall((data:PlayProcessData)=>{this.setPlayProgress(data);this.updateCardData(false,data.isPlay,params.formId);});this.updateCardData(true,AppStorage.get('isPlay'),params.formId);}returnnull;};onCreate(want:Want,launchParam):void{//注册回调函数this.callee.on('METHOD_PLAY_PAUSE',this.playOrPauseCallBack);this.callee.on('METHOD_INIT_CARD',this.initCardCallBack);MusicService.getInstance().initAudioPlayer(this.createSongData());}onDestroy():void{this.callee.off('METHOD_INIT_CARD');this.callee.off('METHOD_PLAY_PAUSE');MusicService.getInstance().release();}}任务代码:WidgetCard.ets(文件8-2)卡片页面。通过@LocalStorageProp绑定卡片数据,点击播放按钮触发call事件,点击其他区域触发router事件拉起应用。@Entry@ComponentstructWidgetCard{readonlyABILITY_NAME:string='EntryAbility';@LocalStorageProp('isPlay')isPlay:boolean=false;@LocalStorageProp('photo')photo:ResourceStr='';@LocalStorageProp('title')title:string='';@LocalStorageProp('singer')singer:string='';@LocalStorageProp('formId')formId:string='';build(){Row(){Column({space:5}){Image(this.photo).size({height:'50%'})Row(){Text(this.title).fontSize(10).fontColor(Color.White)Text('-'+this.singer).fontSize(10).fontColor(Color.White)}//播放/暂停按钮:触发call事件Image(this.isPlay?$r('app.media.ic_public_pause'):$r('app.media.ic_public_play')).width(32).onClick(()=>{postCardAction(this,{action:'call',abilityName:this.ABILITY_NAME,params:{method:'METHOD_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论