首页 > 其他分享 >【HarmonyOS】低代码开发之FA卡片开发流程

【HarmonyOS】低代码开发之FA卡片开发流程

时间:2023-06-28 10:44:19浏览次数:39  
标签:getInstance 卡片 HarmonyOS DataInstance private formId FA 开发 public

1开发准备

1.1FA卡片开发注意事项

参考文档:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-service-widget-provider-js-0000001150602175

1、只定义一个FA卡片

首先通过DevEco Studio创建一个工程,创建完成之后,找到src/main/config.json文件,

在config.json配置文件中,在module--->abilities--->forms节点下,只有一条数据。

forms节点下的isDefault字段值为true,表示该卡片为默认卡片,每个Ability有且只有一个默认卡片。

备注:forms节点的数据结构是数组,这里的要求是内部只有一个{}对象数据。

cke_2508.png

2、提供多种尺寸

在forms节点下的supportDimensions字段中配置多种尺寸,比如这里配置了1*2和2*2两种尺寸:

cke_3523.png

3、对应卡片的js相关资源

“js”模块中的name字段要与“forms”模块中的jsComponentName字段的值一致,为js资源的实例名。

cke_5033.png

4、添加相应权限

例如:卡片需要请求网络数据,需要添加相应的网络权限,打开config.json文件,在module节点下添加reqPermissions节点,如下图所示:

cke_6764.png

5、快照

需要在元服务开发态默认将快照图定义成和2*2卡片相同的内容,用于对新用户展示。

 

1.2低码SDK初始化

基于景区模板开发可以跳过此步骤,低码模板中已经有低码SDK。

在项目工程的根目录下build.gradle文件中的dependencies闭包中添加如下依赖:

cke_8867.png

在entry的根目录下的build.gradle文件的头部添加以下内容:

apply plugin: 'com.huawei.agconnect'

同时在dependencies闭包中添加低码SDK的依赖:

cke_13280.png

在entry/src/main/java/包名/MyApplication.java文件中进行SDK初始化:

cke_16275.png

 

1.3数据模型初始化

基于景区模板开发可以跳过此步骤,此步骤主要介绍如何在云侧创建数据模型。

登录AppGallery Connect控制台,找到对应的项目,然后选中低代码平台中的数据模型,点击新建数据模型:

cke_20447.png

之后点击编辑,为该数据模型添加所需的字段:

cke_24112.png

所需的数据字段创建完成之后,点击保存。

回到数据模型列表所在页面,点击管理数据,之后点击新建,创建以上数据模型所需的数据:

cke_28187.png

在所需的数据全部添加完成之后,数据模型就创建完成了。

 

1.4差异化内容展示方案

第一种:负一屏通过AGC自定义参数

在云侧数据模型中创建了extraParam这个预留参数字段(注意:此处可以创建多个字段,需要和AGC管理台位置感应服务中创建的字段保持一致),通过在AGC管理台---位置感应服务---服务申请中创建相应的字段,端侧获取该字段值,通过对不同值进行判断处理,控制端侧卡片展示不同样式内容。

第二种:小艺建议通过不同POI ID

在云侧数据模型中创建了poi_id字段(字段名称需要根据实际创建),端侧获取该字段值,通过对不同值进行判断处理,小艺建议通过不同POI ID实现控制端侧卡片展示不同的样式内容。

AGC管理台定义的数据和POI ID的数据通过onCreateForm(Intent intent)方法中的intent获取,比如:String poi_id = intent.getStringParam(“poi_id”);

 

2开发卡片

2.1卡片目录结构

卡片的典型开发目录结构如下图所示,详细介绍参见文件组织

cke_32730.png

目录中主要文件夹如下:

  • pages:用于存放卡片的页面。
  • common:用于存放公共资源文件,比如:图片资源。
  • resource:用于存放资源配置文件,比如:多分辨率加载配置文件。
  • i18n:用于配置不同语言场景下资源内容,比如:应用文本词条、图片路径等。

目录中文件分类如下:

  • .hml结尾的HML模板文件:用于描述卡片页面的布局结构。
  • .css结尾的CSS样式文件:用于描述页面的样式。
  • .json结尾的JSON文件:用于配置卡片中使用的变量action事件。

 

2.2布局卡片

在index.hml文件中实现卡片的页面布局。最外层使用div组件和stack组件。stack组件内部使用了两个div组件分别布局1x2和2x2两种不同大小的卡片样式,并且绑定click事件。1x2格式卡片为左右结构,左侧text组件显示标题,右侧Image组件显示播放按钮,绑定消息事件。2x2格式卡片为上下结构,上方text组件显示标题,下方Image组件显示播放按钮,并且绑定消息事件。

<div class="container">
<stack style="height: 100%;width: 100%;">
<div class="item-container-small" show="{{smallCard}}" "routerEvent">
  <text class="title-small">{{title}}</text>
<image src="{{btnSrc}}" class="btn-img-small" "messageEvent"></image>
</div>
<div class="item-container-normal" show="{{normalCard}}" "routerEvent">
<text class="title-normal">{{title}}</text>
<image src="{{btnSrc}}" class="btn-img-normal" "messageEvent"></image>
</div>
</stack>
</div>

2.3设置卡片样式

在index.css文件中定义页面样式,除通用样式外,各组件还可以定义自己特有的样式。例如:text组件设置font-size。组件样式的设置参见各组件的详细介绍。

.container {
flex-direction: column;
justify-content: center;
align-items: center;
}
.title-small {
font-size: 12fp;
margin-start: 15px;
}
.title-normal {
margin-top: 30px;
font-size: 20fp;
}
.item-container-small {
   width: 100%;
   height: 100%;
align-items: center;
}
.item-container-normal {
   width: 100%;
   height: 100%;
align-items: center;
flex-direction: column;
}
.btn-img-small {
margin-start: 25px;
   width: 32px;
   height: 32px;
}
.btn-img-normal {
margin-top: 20px;
   width: 64px;
   height: 64px;
}

2.4配置卡片事件

在index.json文件中配置卡片使用的变量和事件,在data字段中声明变量,在actions字段中声明事件。

本示例在action中定义了名为“routerEvent”的事件,事件类型为“router”,用于跳转到MainAbility。更多用户自定义事件可以使用action:"message"实现。

{
 "data": {
   "smallCard": false,
   "normalCard": true,
   "type": "",
   "title": "",
   "btnSrc": ""
 },
 "actions": {
   "routerEvent": {
     "action": "router",
     "bundleName": "com.lowcode.scenicarea",
     "abilityName": "com.lowcode.scenicarea.MainAbility",
     "params": {
       "message": "add detail"
     }
   },
   "messageEvent": {
     "action": "message",
     "params": {
       "message": "play"
     }
   }
 }
}

除了通过页面主动触发事件,还可以通过卡片各生命周期的回调函数来实现业务处理。卡片生命周期回调在卡片对应的PageAbility中,本示例对应的pageAbility为com.lowcode.scenicarea.MainAbility。在MainAbility的卡片创建回调函数onCreateForm中通过Intent获取卡片的ID、name等信息:

cke_60217.png

public class MainAbility extends AceAbility {
   public static final int DEFAULT_DIMENSION_2X2 = 2;
   private static final int INVALID_FORM_ID = -1;
   private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, MainAbility.class.getName());
   private String topWidgetSlice;
   @Override
   protected ProviderFormInfo onCreateForm(Intent intent) {
       HiLog.info(TAG, "onCreateForm");
       String formName = intent.getStringParam(AbilitySlice.PARAM_FORM_NAME_KEY);
       int dimension = intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY, DEFAULT_DIMENSION_2X2);
       HiLog.info(TAG, "onCreateForm: formId=" + formId + ",formName=" + formName);
       FormControllerManager formControllerManager = FormControllerManager.getInstance(this);
       FormController formController = formControllerManager.getController(formId);
       formController = (formController == null) ? formControllerManager.createFormController(formId,
               formName, dimension) : formController;
       if (formController == null) {
           HiLog.error(TAG, "Get null controller. formId: " + formId + ", formName: " + formName);
           return null;
       }
       return formController.bindFormData(formId);
   }
   ...
}

2.5低码获取数据模型数据

创建数据模型端侧数据实体CardInfo.java:

public class CardInfo {
private String id;
private String type;
private String title;
private String btnSrc;
private String extraParam;
private String poi_id;
      setter(); // 定义各个变量的setter方法
      getter(); // 定义各个变量的getter方法
}

创建获取数据模型端侧数据工具类DataUtil.java:

public class DataUtil {
private static final HiLogLabel TAG = new HiLogLabel(HiLog.INFO, 0x00201, "jscard");

public static List<CardInfo> getData() {
List<CardInfo> mCardInfos = new ArrayList<>();
DataModelRequest request = new DataModelRequest();
request.setModelId("1179644081647666113");
request.setStatus(0);
request.setMethodName("list");
DataModelReqParams params = new DataModelReqParams();
params.setOrderBy("id");
params.setOrderType("asc");
request.setParams(params);
HarmonyTask<DataModelResponse> task = AGConnectLowCode.getInstance().callDataModel(request);
task.addOnCompleteListener(new OnHarmonyCompleteListener<DataModelResponse>() {
@Override
public void onComplete(HarmonyTask<DataModelResponse> harmonyTask) {
               if (harmonyTask.isSuccessful()) {
                   DataModelResponse response = harmonyTask.getResult();
                   List<Map<String, Object>> list = response.getData().getRecords();
                   mCardInfos.clear();
                   for (Map<String, Object> map : list) {
                       CardInfo cardInfo = new CardInfo();
cardInfo.setId(map.get("id").toString());
cardInfo.setType(map.get("type").toString());
cardInfo.setTitle(map.get("title").toString());
cardInfo.setBtnSrc(map.get("btnSrc").toString());
cardInfo.setExtraParam(map.get("extraParam").toString());
cardInfo.setPoi_id(map.get("poi_id").toString());
                       mCardInfos.add(cardInfo);
                   }
                   HiLog.info(TAG, "success");
               } else {
                   HiLog.info(TAG, "fail");
               }
}
});
return mCardInfos;
   }
}

创建单例管理类DataInstance.java用来管理数据和Player播放器:

public class DataInstance {
private static class SingletonHolder {
private static final DataInstance INSTANCE = new DataInstance();
   }

private DataInstance () {}

public static final DataInstance getInstance() {
return SingletonHolder.INSTANCE;
   }

private List<CardInfo> list;
private Player player;

private boolean isPlay= false;

public boolean isPlay() {
return isPlay;
   }

public void setPlay(boolean play) {
isPlay = play;
   }

public Player getPlayer() {
return player;
   }

public void setPlayer(Player player) {
this.player = player;
   }

public List<CardInfo> getList() {
return list;
   }

public void setList(List<CardInfo> list) {
this.list = list;
   }
}

2.6初始化卡片

首先在MainAbility.java类的onStart()方法中初始化数据和播放器:

public class MainAbility extends AceAbility {
public static final int DEFAULT_DIMENSION_2X2 = 2; //System-defined constant. Do not change its value.
private static final int INVALID_FORM_ID = -1;
private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, "jscard");
private String topWidgetSlice;
private Player mPlayer;

@Override
public void onStart(Intent intent) {
super.onStart(intent);
DataInstance.getInstance().setList(DataUtil.getData());
initPlayer();
   }

@Override
public void onStop() {
super.onStop();
   }

private void initPlayer() {
if (mPlayer == null) {
mPlayer = new Player(this);
}
DataInstance.getInstance().setPlayer(mPlayer);
Source source = new Source("https://www.cambridgeenglish.org/images/153149-movers-sample-listening-test-vol2.mp3");
DataInstance.getInstance().getPlayer().setSource(source);
DataInstance.getInstance().getPlayer().prepare();
   }

@Override
protected ProviderFormInfo onCreateForm(Intent intent) {
HiLog.info(TAG, "onCreateForm");
long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);
String formName = intent.getStringParam(AbilitySlice.PARAM_FORM_NAME_KEY);
int dimension = intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY, DEFAULT_DIMENSION_2X2);
HiLog.info(TAG, "onCreateForm: formId=" + formId + ",formName=" + formName);
FormControllerManager formControllerManager = FormControllerManager.getInstance(this);
FormController formController = formControllerManager.getController(formId);
formController = (formController == null) ? formControllerManager.createFormController(formId,
               formName, dimension) : formController;
if (formController == null) {
HiLog.error(TAG, "Get null controller. formId: " + formId + ", formName: " + formName);
return null;
}
if (DataInstance.getInstance().getList()==null || DataInstance.getInstance().getList().size()==0){
DataInstance.getInstance().setList(DataUtil.getData());
initPlayer();
}
return formController.bindFormData(formId);
	}
	……
}

在WidgetImpl.java类的bindFormData()方法中初始化卡片展示:

private Context mContext;
public WidgetImpl(Context context, String formName, Integer dimension) {
super(context, formName, dimension);
HiLog.info(TAG, "WidgetImpl");
this.mContext = context;
   }

@Override
   public ProviderFormInfo bindFormData(long formId) {
HiLog.info(TAG, "bind form data");
ZSONObject object = new ZSONObject();
if (dimension == DIMENSION_1X2) {
object.put("smallCard", true);
object.put("normalCard", false);
object.put("type", DataInstance.getInstance().getList().get(0).getType());
object.put("title", DataInstance.getInstance().getList().get(0).getTitle());
if (!DataInstance.getInstance().isPlay()){
       object.put("btnSrc", DataInstance.getInstance().getList().get(0).getBtnSrc());
}else {
               object.put("btnSrc", DataInstance.getInstance().getList().get(1).getBtnSrc());
}
} else if (dimension == DIMENSION_2X2) {
object.put("smallCard", false);
object.put("normalCard", true);
object.put("type", DataInstance.getInstance().getList().get(2).getType());
object.put("title", DataInstance.getInstance().getList().get(2).getTitle());
if (!DataInstance.getInstance().isPlay()){
               object.put("btnSrc", DataInstance.getInstance().getList().get(2).getBtnSrc());
}else {
               object.put("btnSrc", DataInstance.getInstance().getList().get(3).getBtnSrc());
}
}
FormBindingData bindingData = new FormBindingData(object);
ProviderFormInfo formInfo = new ProviderFormInfo();
formInfo.setJsBindingData(bindingData);
return formInfo;
   }

2.7卡片效果展示

cke_212422.png​​

2.8音乐播放/暂停事件

此部分功能同样在WidgetImpl.java类中实现:

创建音乐播放/暂停的方法:

// 暂停音乐
private void pause() {
	DataInstance.getInstance().getPlayer().pause();
}

// 播放音乐
private void play() {
	DataInstance.getInstance().getPlayer().play();
}

音乐播放/暂停时更新播放按钮的图片资源:

// 更新数据
private void updateForm(long formId, String btnSrc) {
ZSONObject object = new ZSONObject();
object.put("btnSrc", btnSrc);
try {
if (mContext instanceof Ability) {
         ((Ability) mContext).updateForm(formId, new FormBindingData(object));
}
} catch (FormException e) {
HiLog.error(TAG, e.getMessage());
}
}

在2.4中配置了卡片的消息事件,通过消息事件触发音乐播放,在onTriggerFormEvent()方法中接收事件并处理播放/暂停及按钮的样式更新逻辑:

@Override
public void onTriggerFormEvent(long formId, String message) {
HiLog.info(TAG, "onTriggerFormEvent");
if (!TextUtils.isEmpty(message)){
ZSONObject zsonObject = ZSONObject.stringToZSON(message);
   String msg = zsonObject.getString("message");
if (!TextUtils.isEmpty(msg) && "play".equals(msg)){
               if (!DataInstance.getInstance().isPlay()){
DataInstance.getInstance().setPlay(true);
                   if (dimension==DIMENSION_1X2){
updateForm(formId,DataInstance.getInstance().getList().get(1).getBtnSrc());
                   }else if (dimension==DIMENSION_2X2){
updateForm(formId,DataInstance.getInstance().getList().get(3).getBtnSrc());
                   }
                   play();
               }else {
DataInstance.getInstance().setPlay(false);
                   if (dimension == DIMENSION_1X2){
                       updateForm(formId,DataInstance.getInstance().getList().get(0).getBtnSrc());
                   }else if (dimension==DIMENSION_2X2){
updateForm(formId,DataInstance.getInstance().getList().get(2).getBtnSrc());
                   }
           pause();
               }
}
}
}

最后来看一下播放的效果:

cke_225846.png​​

标签:getInstance,卡片,HarmonyOS,DataInstance,private,formId,FA,开发,public
From: https://www.cnblogs.com/mayism123/p/17510774.html

相关文章

  • 大语言模型的开发利器langchain
    目录简介什么是langchainlangchain的安装langchain快速使用构建应用聊天模式Prompt的模板ChainsAgentsMemory总结简介最近随着chatgpt的兴起,人工智能和大语言模型又再次进入了人们的视野,不同的是这一次像是来真的,各大公司都在拼命投入,希望能在未来的AI赛道上占有一席之地。因为A......
  • VS开发Qt界面项目—— 一些注意事项
    1、VS新建Qt项目时,ui使用指针、类名保持VS习惯首字母大写2、将ui_*.h文件添加进项目(项目\x64\Debug\uic\ui_*.h),以便ui->智能提示。 3、设置VS里双击ui文件直接用QtCreator打开,而不是QtDesigner。VS解决方案ui文件处,鼠标右键,打开方式(N)... 4、防中文乱码。main.cpp中......
  • 一文总结高并发大数据量下MySQL开发规范【军规】
    在互联网公司中,MySQL是使用最多的数据库,那么在并发量大、数据量大的互联网业务中,如果高效的使用MySQL才能保证服务的稳定呢?根据本人多年运维管理经验的总结,梳理了一些基础的开发规范,希望能给大家带来一些帮助。一、基础规范数据库字符集默认使用utf8mb4,兼容utf8,并支持存储emoji......
  • 为什么现代的低代码开发平台都不支持导出源代码?
    摘要:本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。初次接触低代码的程序员大多会纠结一个问题,为什么功能越强大的低代码开发平台越不会提供导出源代码的功能?要想回答这个问题,我们得回顾一......
  • 利用Pytorch实现Faster R-CNN
    代码解析: Pytorchtorchvision构建Faster-rcnn(一)----coco数据读取Pytorchtorchvision构建Faster-rcnn(二)----基础网络Pytorchtorchvision构建Faster-rcnn(三)----RPNPytorchtorchvision构建Faster-rcnn(四)----ROIHead训练模型:BaiduCloud 附加Pytorch源码:https://github.com/chen......
  • 阿里的Java开发规范插件验证
    阿里最近有点“烦”,但是作为技术人,更多关注的还是技术层面,其他的就交给有关机构和时间来证明。最近有项工作借鉴了阿里的Java开发规范,为了能让其落地,需要验证方案,而这个Java开发规范提供了对应的验证插件,因此从使用层面,了解一下。目前该插件实现了开发手册中的的53条规则,大部分基于......
  • vue3标准开发过程
    1.如何用脚手架快速新建一个vue3项目安装vue-cli后,用如下命令创建 vuecreatemy-vue3-project 默认创建vue3项目,直接回车即可。 新建完成后,如何引入element-plus? 用Webstrom打开项目,先运行一次npminstall然后运行npminstallelement-plus--save 然后打开m......
  • python的django框架开发简单的管理系统(一)
    写在最前面:博主现在大二,也不是名校。刚刚接触电脑的时候,装个虚拟机都能搞崩溃。WPS甚至不知道怎么保存,以为发文件的之前关闭,文件就没了。一把辛酸泪啊读者们不必妄自菲薄。废话少说,直接开始。准备:安装python解释器提供3.10,3.9.3.11。尽量选3.9或者3.10:链接:https://pan.baidu.com......
  • 全栈测试开发系列----WebDriver API及对象识别技术(一)
    前言:WebDriverAPI相比于之前的selenium-RCAPI而言,不仅解决了一些相关的限制,还使得接口更加简洁,同时更好的支持了页面本身不重新加载而页面元素发生变化的动态网页,所以WebDriverAPI的实现目的不仅是提供一个良好的面向对象API,而且对Web应用程序测试过程中所产生的问题......
  • Spring Boot应用开发初探与示例
    SpringBoot是由Pivotal团队提供的全新Spring开发框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。从它的名字可以看出,SpringBoot的作用在于创建和启动新的基于Spring框架的项目。它的目的是帮助开发人员很容易的创建出独立运行和产品级别的基于Spring框架的应......