更多信息请访问:https://harmonyos.51cto.com,与华为官方共同建立的鸿蒙技术社区Ability)是一种界面展示形式,将重要信息或操作放在卡上的FA(FeatureAbility),从而实现直接服务,降低体验等级。卡片常用于嵌入其他应用程序(目前仅支持系统应用程序)作为其界面的一部分显示,并支持拉起页面、发送消息等基本交互功能。本期Codelab,我们将介绍如何在HarmonyOS上开发时钟服务卡应用。该卡片采用Java开发语言开发,包括2×2和2×4布局两种显示形式。我们先来看看。它显示出来了。下面我们将重点介绍卡片应用的创建、更新和删除,卡片数据库(用于存储卡片信息)的创建和使用,以及卡片数据服务的使用和更新。在开始编码之前,开发者需要先下载并安装HuaweiDevEcoStudio。可以参考官网指南:HuaweiDevEcoStudio安装指南:https://developer.harmonyos.com/cn/docs/documentation/docguides/software_install0000001053582415本Codelab主要完成配置语句、页面布局、功能逻辑entry\src\main\java\目录下的代码实现。整个项目的代码结构如下:database文件夹是开发者创建的文件夹,包含两个java文件——Form和FormDatabase。其中,Form为卡片对象,用于存储卡片id、卡片名称和卡片规格。FormDatabase是一个卡片数据库对象,用于创建卡片数据库。●slice文件夹只包含ClockCardSlice文件,它是应用程序的主页面。●utils文件夹是开发者创建的文件夹,用于存放各种打包好的工具。在此Codelab中,包含了ComponentProviderUtils、DatabaseUtils、DateUtils和LogUtils。其中,ComponentProviderUtils提供了获取更新卡片的ComponentProvider对象的方法;DatabaseUtils提供了数据库相关操作的方法;DateUtils提供了日期相关操作的方法;LogUtils封装了日志工具类。●DevEcoStudio生成的MainAbility主程序入口,用于重写创建、删除卡片等方法。●MyApplicationDevEcoStudio生成时没有任何变化。●TimerAbility是一个ServiceAbility,需要开发者自己创建来更新时钟。●布局文件夹是页面布局文件夹。由于时钟卡Codelab涉及两种尺寸:2×2和2×4,因此需要为页面布局创建两个新的.xml文件。●config.json配置文件,用于卡和服务能力的声明。了解了项目代码结构后,我们来一一讲解其中的关键步骤。1.配置文件在卡片应用开发之前,我们需要在其配置文件config.json中进行如下声明,以便系统识别该应用为卡片应用并绑定到系统中。在卡片所在的“abilities”中,需要配置“formsEnabled”:true和“visible”:true才能识别为卡片。同时需要配置forms模块的详细信息,代码如下:"abilities":[{....."formsEnabled":true,//表示该能力支持服务卡显示"visible":true,"forms":[{"landscapeLayouts":["$layout:form_image_with_info_date_card_2_2","$layout:form_image_with_info_date_card_2_4"],//表示卡片外观规范对应的水平布局文件,只有当卡片类型是Java卡,需要配置这个标签"isDefault":true,//卡是默认卡"scheduledUpdateTime":"10:30","defaultDimension":"2*2",//默认外观卡片的规格,这里是2*2"name":"DateCard",//卡片的类名"description":"Thisisaservicewidget",//卡片的描述"colorMode":"auto","type":"Java",//表示卡的类型,这是java卡"supportDimensions":["2*2","2*4"],//表示卡支持的外观规格,这里是2*2和2*4"画像itLayouts":["$layout:form_image_with_info_date_card_2_2","$layout:form_image_with_info_date_card_2_4"],//表示卡片外观规格对应的垂直布局文件,只有当卡片类型为Java卡片时,标签"upda"才需要被配置teEnabled":true,//表示支持周期刷新,可以定时刷新"updateDuration":1,//表示卡片定时刷新的更新周期,单位是30分钟,这里是30分钟刷新一次minutes"formVisibleNotify":true}]forms模块相关属性的说明,开发者可以参考官网资料●Javacard开发指南https://developer.harmonyos.com/cn/docs/documentation/docguides/abilityservicewidgetproviderjava00000011040822202.Cardlayout本Codelab为card应用设计了2×2和2×4两种布局样式,效果如下如下图:其中2×2的布局分为四行,从上到下显示的内容分别是日期、时间描述内容、时间具体信息、星期。整体由四个DirectionalLayout嵌套在DependentLayout布局中组成。每个DirectionalLayout都使用Text组件显示。部分代码示例如下:<文本...>2×4布局分为三行,日期和星期合为一行,时间描述内容和时间具体信息列为一行。整体布局由一个DependentLayout和嵌套在DependentLayout布局中的两个DirectionalLayout组成。其中,DependentLayout布局由一个Text组件和一个DirectionalLayout组成,DirectionalLayout中嵌套了七个Text组件。另外两个DirectionalLayouts使用Text组件进行显示。部分代码示例如下:3.卡片数据库的创建和卡片数据服务卡片数据库的创建本Codelab使用对象关系映射数据库来存储卡片ID、卡片名称等信息。因此,我们需要创建一个数据库(FormDatabase)和一个表(Form)。其中,对象关系映射(ORM)数据库类对应关系型数据库,即本Codelab中的FormDatabase.java,用于存储“Form”表,版本号为“1”。在使用ORM数据库之前,您需要创建一个继承自OrmDatabase的数据库类,并使用@Database注解。示例代码如下:@Database(entities={Form.class},version=1)publicabstractclassFormDatabaseextendsOrmDatabase{}关于OrmDatabase的开发,开发者可以参考官网资料。●OrmDatabasehttps://developer.harmonyos.com/cn/docs/documentation/doreferences/ormdatabase0000001054838766另外我们在对象关系映射(ORM)数据库中定义一个实体类Form.java,对应数据库中的表名“表单”,包括卡片编号(formId)、卡片名称(formName)和卡片规格(dimension)三个字段。在操作ORM数据库中的实体之前,需要先创建一个继承自OrmObject的实体类,并用@Entity注解。示例代码如下:@Entity(tableName="form")publicclassFormextendsOrmObject{@PrimaryKey()privateLongformId;privateStringformName;privateIntegerdimension;publicForm(LongformId,StringformName,Integerdimension){this.formId=formId;//cardidthis.formName=formName;//卡片名称this.dimension=dimension;//卡片规格}publicForm(){}publicIntegergetDimension(){returndimension;}publicvoidsetDimension(Integerdimension){this.dimension=dimension;}publicLonggetFormId(){returnformId;}publicvoidsetFormId(LongformId){this.formId=formId;}publicStringgetFormName(){returnformName;}publicvoidsetFormName(StringformName){this.formName=formName;}}OrmObject相关的开发信息,开发者可以参考官网信息。●OrmObjecthttps://developer.harmonyos.com/cn/docs/documentation/doreferences/ormobject0000001054120141卡片数据服务的创建由于我们开发的时钟服务卡片需要每秒刷新一次,为了方便时钟卡片刷新的定时任务,我们需要在目录下右键new>Ability>EmptyServiceAbility,创建一个名为TimerAbility的ServiceAbility作为卡片更新定时器,每秒更新一次:@OverridepublicvoidonStart(Intentintent){HiLog.info(LABEL_LOG,"TimerAbility::onStart");connect=helper.getOrmContext("FormDatabase","FormDatabase.db",FormDatabase.class);startTimer();super.onStart(intent);}//卡片更新定时器,每秒更新一次privatevoidstartTimer(){Timertimer=newTimer();timer.schedule(newTimerTask(){@Overridepublicvoidrun(){updateForms();}},0,SEND_PERIOD);}同时,TimerAbility还承担了卡片更新功能,我们就可以了下面将详细介绍。4.时钟卡片应用的创建、更新、删除在正式进入时钟FA卡片创建、更新、删除的开发之前,我们先了解一下卡片开发的一些基本概念。服务卡总体框架主要包括三部分:卡用户、卡管理服务和卡提供者。卡片用户:显示卡片内容的宿主应用,控制卡片在宿主中的显示位置。卡片管理服务:用于管理系统中添加的卡片的常驻代理服务,包括卡片对象的管理和使用、卡片的周期刷新等。控制卡片显示内容,控制布局,控制点击事件。开发卡的开发者是卡提供者。请注意,卡用户和提供者不需要永久操作。当需要添加/删除/请求更新卡片时,卡片管理服务会拉取卡片提供商获取卡片信息。卡片创建当卡片用户请求获取卡片时,卡片提供者会被拉起并调用onCreateForm回调函数。Intent中会包含卡片ID、卡片名称和卡片外观规格信息,通过AbilitySlice.PARAM_FORM_IDENTITY_KEY、AbilitySlice.PARAM_FORM_NAME_KEY和AbilitySlice.PARAM_FORM_DIMENSION_KEY获取,根据卡片名称和外观规格获取对应的xml布局,构造卡片对象,完成卡片信息的创建。MainAbility中有如下示例代码:@OverrideprotectedProviderFormInfoonCreateForm(Intentintent){if(intent==null){returnnewProviderFormInfo();}//获取卡片IDformId=INVALID_FORM_ID;if(intent.hasParameter(AbilitySlice.PARAM_FORM_IDENTITY_KEY)){formId=intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY,INVALID_FORM_ID);}else{returnnewProviderFormInfo();}//获取卡片名称StringformName=EMPTY_STRING;if(intent.hasParameter(AbilitySlice.PARAM_FORM_NAME_KEY)){formName=intent.getSStringParam_NAME_KEY){formName=intent.getSStringParam_NAME_KEY){formName=intent.getSStringParam_NAME_KEY);}//获取卡片规格intdimension=DEFAULT_DIMENSION_2X2;if(intent.hasParameter(AbilitySlice.PARAM_FORM_DIMENSION_KEY)){dimension=intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY,DEFAULT_DIMENSION_2X2);}intlayoutId=ResourceTable.Layout_form_image_with_info_date_card_2_2;if(dimension==DEFAULT_DIMENSION_2X4){layoutId=ResourceTable.Layout_form_image_with_info_date_card_2_4;}formInfo=newProviderFormInfo(layoutId,this);//存储卡片信息formform=newForm(formId,formName,dimension);ComponentProvidercomponentProvider=ComponentProviderUtils.getComponentProvider(form,this);formInfo.mergeActions(componentProvider);if(connect==null){connect=helper.getOrmContext("FormDatabase","FormDatabase.db",FormDatabase.class);}尝试{DatabaseUtils.insertForm(form,connect);}catch(Exceptione){DatabaseUtils.deleteFormData(form.getFormId(),connect);}returnformInfo;}卡片更新服务有两种卡片刷新机制,第一种是定时/固定-点更新,即在config.json中配置定时/定点更新后,卡片管理服务会定时拉起服务卡片刷新数据。第二种是主动更新,即开发者根据需要主动调用updateForm方法更新卡片。在本Codelab中,我们选择第二种方式。我们在之前创建的TimerAbility.java中调用updateForm方法从数据表Form中获取卡片信息,并更新时分秒:privatevoidupdateForms(){//从数据库中获取卡片信息OrmPredicatesormPredicates=newOrmPredicates(Form.class);List