[文章]

#HarmonyOS征文#鸿蒙卡片-物联网DTU污水液位计卡片

2021-6-26 08:59:30  685 HarmonyOS 征文 物联网
分享
3

效果视频:假如中国空间站用上了鸿蒙系统

1.效果视频:假如中国空间站用上了鸿蒙系统

2.效果视频:哔哩哔哩弹幕姬鸿蒙版

视频里面是液位计卡片的翻版(改改字)
gitee地址:因为应用准备上架暂不提供源码



目录
1.前言&项目背景
2.服务卡片的UI设计
  2.1尺寸选择
  2.2内容构成
  2.3污水液位计卡片原型设计
3.基本概念
  3.1卡片使用方
  3.2卡片管理服务
  3.3卡片提供方
4.运作机制
  4.1卡片管理服务包含以下模块
  4.2卡片提供方包含以下模块
5.服务卡片开发环境搭建和基本页面开发
  5.1开发环境
  5.2新建HarmonyOS手机项目
  5.3卡片基础配置
  5.4卡片基础界面编写代码
6.服务卡片基本开发教程
  6.1增加点击跳转查看详情页面
  6.2增加简单的长按编辑页面
  6.3数据手动刷新
7.服务卡片进阶开发教程
  7.1数据定时刷新
  7.2编辑页面开发&编辑更新卡片逻辑开发
  7.3自定义刷新策略
8.小卡片和硬件HI3861交互
9.分布式卡片开发
10.哔哩哔哩弹幕姬鸿蒙版

1. 前言&项目背景
鸿蒙在手机beta3中新增了桌面卡片,我也是在第一时间体验了一下新浪新闻鸿蒙版的新闻小卡片,我觉得非常有意思,并且我觉得可以用在物联网项目的污水液位计的液位展示中,可以实现碰一碰获取液位计数据展示在小卡片中。
HarmonyOS推出的服务卡片,是FA(Feature Ability)的界面展现形式,将FA的重要信息或者操作前置到卡片上,以达到服务直达的目的。
系统自带卡片实际界面如下图所示:

2. 服务卡片的UI设计
2.1尺寸选择
鸿蒙的服务卡片尺寸分别为:微(1×2)、小( 2×2 )、中( 2×4 )、大(4×4)4种尺寸。

服务卡片示例-From:作者:zengsi,华为软件开发工程师
污水液位计卡片展示数据比较少,所以我选了2×2的小卡片,和2×4的小卡片。2*2的小卡片主要是展示的是单个液位计的数据,而2×4的小卡片展示的是多个液位计的数据的总体展示
2.2 内容构成
服务卡片由多种设计元素组合而成,以下7种常见信息元素可以作为内容选择:
图标、数据、文本、按钮、图片、宫格、列表
污水液位计卡片我觉得主要展示的是当前的液位和液位计的历史曲线,所以我这个污水液位计卡片由数据、文本、曲线图、列表和按钮组成。
2.3 污水液位计卡片原型设计
采用水平垂直居中的布局,因为重要的数据是当前液位,所以当前液位采用18px的黑色字体,点击查看详情用是#53A7F3颜色的15px字,曲线使用#53A7F3颜色更显科技感
3. 基本概念
3.1 卡片使用方
显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
3.2 卡片管理服务
用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。
3.3 卡片提供方
提供卡片显示内容的HarmonyOS应用或原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。
来自:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-service-widget-overview-0000001062607955
4. 运作机制

卡片管理服务包含以下模块:
  • 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。
  • 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延
  • 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。
  • 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。
  • 通信适配层:负责与卡片使用方和提供方进行RPC通信。


卡片提供方包含以下模块:
  • 卡片服务:由卡片提供方开发者实现,开发者实现onCreateForm、onUpdateForm和onDeleteForm处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。
  • 卡片提供方实例管理模块:由卡片提供方开发者实现,负责对卡片管理服务分配的卡片实例进行持久化管理。
  • 通信适配层:由HarmonyOS SDK提供,负责与卡片管理服务通信,用于将卡片的更新数据主动推送到卡片管理服务。
来自:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-service-widget-overview-0000001062607955

5. 服务卡片开发环境搭建和基本页面开发
5.1 开发环境
1.一台升级了鸿蒙2.0的手机/登录华为开发者账号使用远程模拟器
2.下载安装DevEco Studio 2.1 Release
DevEco下载安装教程:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/installation_process-0000001071425528
因为本文的重点是卡片,deveco安装教程和真机调试请看下面我的教程
https://blog.csdn.net/qq_33259323/article/details/112405157
5.2 新建HarmonyOS手机项目API选择5,show in service senter打勾

5.3 卡片基础配置
然后打开配置文件src/main/config.json,配置你所需要的卡片样式,详细配置请看
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/basic-config-file-elements-0000000000034463#ZH-CN_TOPIC_0000001064016070__table8276925145611

我这边选择的是2*2的小卡片,其他的都是默认所以只需要改一下名字和描述,注意文件夹名字要和name对应,如果不对应就是白卡片

5.4 卡片基础界面编写代码
编写hml,通过{{}}绑定index.json里面的数据
  1. <div class="container">
  2.     <div class="title">
  3.         <text class="text_title">1#液位计: </text>
  4.         <text class="text_title">{{temperature}}</text>
  5.         <text class="text_title"> m</text>
  6.     </div>
  7.     <stack class="chart_region">
  8.         <chart class="chart_data" type="line" options="{{lineOps}}" datasets="{{lineData}}"></chart>
  9.     </stack>
  10.     <text class="text_nav">点击查看详情</text>
  11. </div>
复制代码
编写CSS
  1. .container {
  2.     flex-direction: column;
  3.     justify-content: center;
  4.     align-items: center;
  5. }

  6. .title{
  7.     width: 100%;
  8.     height: 30px;
  9.     justify-content: center;
  10. }

  11. .text_title {
  12.     font-size: 15px;
  13. }

  14. .chart_region{
  15.     height: 90px;
  16. }

  17. .chart_data{

  18. }

  19. .text_nav {
  20.     font-size: 15px;
  21.     color: #53A7F3;
  22. }
复制代码

编写JSON

  1. {
  2.   "data": {
  3.     "level": "12",
  4.     "lineData": [
  5.       {
  6.         "strokeColor": "#7fccde",
  7.         "fillColor": "#7fccde",
  8.         "data": [0,10,20,12,13,10,40,10,5,9,14,18,20,30,10,20,10,17],
  9.         "gradient": true
  10.       }
  11.     ],
  12.     "lineOps": {
  13.       "xAxis": {
  14.         "min": 0,
  15.         "max": 15,
  16.         "display": false
  17.       },
  18.       "yAxis": {
  19.         "min": 0,
  20.         "max": 24,
  21.         "display": false
  22.       },
  23.       "series": {
  24.         "lineStyle": {
  25.           "width": "1px",
  26.           "smooth": true
  27.         },
  28.         "headPoint": {
  29.           "shape": "circle",
  30.           "size": 10,
  31.           "strokeWidth": 3,
  32.           "fillColor": "#ffffff",
  33.           "strokeColor": "#7fccde",
  34.           "display": true
  35.         }
  36.       }
  37.     }
  38.   }
  39. }
复制代码
可以先使用预览器看一下界面,或者直接运行
双击打开index.hml,然后点击右侧的预览器

6. 服务卡片基本开发教程
6.1 增加点击跳转查看详情页面
1.在hml增加点击事件
<text class="text_nav">点击查看详情</text>
2.创建需要跳转的Ability(CardFormAbility)

3.编写index.json文件
其中 routerEvent 就是在hml中的onclick属性值,action为router,abilityName为需要跳转到的ability名字

4.编写跳转测试页面
  1. package com.example.phone.ability;

  2. import ohos.ace.ability.AceAbility;
  3. import ohos.aafwk.content.Intent;

  4. public class CardFormAbility extends AceAbility {
  5.     @Override
  6.     public void onStart(Intent intent) {
  7.         setInstanceName("CardForm");
  8.         super.onStart(intent);
  9.     }

  10.     @Override
  11.     public void onStop() {
  12.         super.onStop();
  13.     }
  14. }
复制代码



6.2 增加简单的长按编辑页面
1.创建卡片编辑Ability(LevelCardConfigAbility)
点击File>New>Ability>Page Ability(JS)

在LevelCardConfigAbility.onstart中添加setInstanceName("LevelCardConfig");
  1. package com.example.phone.ability;

  2. import ohos.ace.ability.AceAbility;
  3. import ohos.aafwk.content.Intent;

  4. public class LevelCardConfigAbility extends AceAbility {
  5.     @Override
  6.     public void onStart(Intent intent) {
  7.         setInstanceName("LevelCardConfig");
  8.         super.onStart(intent);
  9.     }

  10.     @Override
  11.     public void onStop() {
  12.         super.onStop();
  13.     }
  14. }
复制代码
在hml中添加示例代码

2.在配置文件中增加属性:formConfigAbility
"formConfigAbility": "ability://com.example.phone.ability.LevelCardConfigAbility"

污水液位计卡片编辑页面详细开发请看:6.9
6.3 数据手动刷新1. 在卡片编辑小卡片添加手动刷新事件
index.hml

index.json

2. 创建CardFormAbility(如果之前已经创建过了就不用创建了)
在src/main/config.json中,如果你的小卡片是卸载MainAbility里面的,就不需要创建这个CardFormAbility,我是为了方便分开来,把卡片配置写在CardFormAbility中

因为是演示代码,所以请求后台服务器获得数据的代码放在ontrigger€€FormEvent中
  1. package com.example.phone.ability;

  2. import ohos.aafwk.ability.FormBindingData;
  3. import ohos.aafwk.ability.FormException;
  4. import ohos.ace.ability.AceAbility;
  5. import ohos.aafwk.content.Intent;
  6. import ohos.hiviewdfx.HiLogLabel;
  7. import ohos.utils.zson.ZSONObject;

  8. public class CardFormAbility extends AceAbility {
  9.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "CardFormAbility");

  10.     @Override
  11.     public void onStart(Intent intent) {
  12.         setInstanceName("CardForm");
  13.         super.onStart(intent);
  14.     }

  15.     @Override
  16.     public void onStop() {
  17.         super.onStop();
  18.     }

  19.     @Override
  20.     protected void onTriggerFormEvent(long formId, String message) {
  21.         // 解析收到的数据
  22.         ZSONObject messageJSON = ZSONObject.stringToZSON(message);

  23.         if(messageJSON.get("message").equals("updata")){       // 更新数据
  24.             ZSONObject zsonObject = new ZSONObject();
  25.             
  26.             // 请求后台服务器获得数据
  27.             zsonObject.put("level", "100");
  28.             
  29.             FormBindingData formBindingData = new FormBindingData(zsonObject);
  30.             try {
  31.                 // 更新数据
  32.                 if (!updateForm(formId, formBindingData)) {

  33.                 }
  34.             } catch (FormException e) {
  35.                 e.printStackTrace();
  36.             }
  37.         }

  38.         super.onTriggerFormEvent(formId, message);
  39.     }
  40. }
复制代码

这样点击index.hml中的标题,就可以更新数据了

7. 服务卡片进阶开发教程
7.1 数据定时刷新
7.1.1 使用鸿蒙自带的定时刷新
1. 数据定时刷新需要在src/main/config.json配置文件中配置,是否开启定时刷新和定时刷新的时间,在6.3中有介绍
"updateEnabLED": true,"updateDuration": 1
2. 编写CardFormAbility,重写onUpdateForm方法
  1. @Override
  2. protected void onUpdateForm(long formId) {
  3.         super.onUpdateForm(formId);
  4.         ZSONObject zsonObject = new ZSONObject();
  5.         zsonObject.put("level", "1.123");
  6.         FormBindingData formBindingData = new FormBindingData(zsonObject);
  7.         // 调用updateForm接口去更新对应的卡片,仅更新入参中携带的数据信息,其他信息保持不变
  8.         try {
  9.             if (!updateForm(formId, formBindingData)) {
  10.                 // err process
  11.             }
  12.         } catch (FormException e) {
  13.             e.printStackTrace();
  14.         }
  15. }
复制代码

7.1.2 自定义刷新策略
请看7.3
7.2 编辑页面开发&编辑更新卡片逻辑开发
1.页面开发
index.hml
  1. <div class="container">
  2.     <text class="title">
  3.         选择液位计
  4.     </text>
  5.     <list class="todo-wraper">
  6.         <list-item for="{{todolist}}" class="todo-item" @click="choose({{$item.id}}})">
  7.             <text class="todo-title">{{$item.title}}</text>
  8.         </list-item>
  9.     </list>
  10. </div>
复制代码
index.css
  1. .container {
  2.     flex-direction: column;
  3.     justify-content: center;
  4.     align-items: center;
  5. }

  6. .title {
  7.     font-size: 40px;
  8.     color: #000000;
  9.     opacity: 0.9;
  10. }

  11. .todo-wraper {
  12.     width: 454px;
  13.     height: 300px;
  14.     margin-top: 20px;
  15. }
  16. .todo-item {
  17.     width: 454px;
  18.     height: 80px;
  19.     flex-direction: column;
  20. }
  21. .todo-title {
  22.     width: 454px;
  23.     height: 40px;
  24.     text-align: center;
  25. }
复制代码
index.js
  1. import prompt from <span class="hljs-string">'@system.prompt'</span>;

  2. <span class="hljs-keyword">const</span> ABILITY_TYPE_EXTERNAL = <span class="hljs-number">0</span>;
  3. <span class="hljs-keyword">const</span> ACTION_SYNC = <span class="hljs-number">0</span>;
  4. <span class="hljs-keyword">const</span> CHOOSE_LEVEL = <span class="hljs-number">1001</span>;

  5. <span class="hljs-comment">// 给CardServiceAbility发送选择的ID</span>
  6. export <span class="hljs-keyword">const</span> CardFormAbility = {
  7.     choose: async <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(id)</span>{</span>
  8.         <span class="hljs-keyword">var</span> action = {};
  9.         action.bundleName = <span class="hljs-string">'com.example.phone'</span>;
  10.         action.abilityName = <span class="hljs-string">'com.example.phone.ability.CardServiceAbility'</span>;
  11.         action.messageCode = CHOOSE_LEVEL;
  12.         action.data = id;
  13.         action.abilityType = ABILITY_TYPE_EXTERNAL;
  14.         action.syncOption = ACTION_SYNC;

  15.         <span class="hljs-keyword">var</span> result = await FeatureAbility.callAbility(action);
  16.         <span class="hljs-keyword">var</span> ret = <span class="hljs-built_in">JSON</span>.parse(result);
  17.         <span class="hljs-keyword">if</span> (ret.code == <span class="hljs-number">0</span>) {

  18.         } <span class="hljs-keyword">else</span> {

  19.         }
  20.     }
  21. }

  22. export <span class="hljs-keyword">default</span> {
  23.     data: {
  24.         title: <span class="hljs-string">""</span>,
  25.         todolist: [{
  26.             title: <span class="hljs-string">'1#液位计'</span>,
  27.             id: <span class="hljs-number">1</span>
  28.         }, {
  29.             title: <span class="hljs-string">'2#液位计'</span>,
  30.             id: <span class="hljs-number">2</span>
  31.         },{
  32.             title: <span class="hljs-string">'3#液位计'</span>,
  33.             id: <span class="hljs-number">3</span>
  34.         }],
  35.     },
  36.     onInit() {
  37.         <span class="hljs-keyword">this</span>.title = <span class="hljs-keyword">this</span>.$t(<span class="hljs-string">'strings.world'</span>);
  38.     },
  39.     choose(id) {
  40.         
  41.         CardFormAbility.choose(id);
  42.     }
  43. }
复制代码

2.编写LevelCardConfigAbility来保存卡片ID
  1. package com.example.phone.ability;

  2. import ohos.aafwk.ability.AbilitySlice;
  3. import ohos.aafwk.content.IntentParams;
  4. import ohos.ace.ability.AceAbility;
  5. import ohos.aafwk.content.Intent;

  6. public class LevelCardConfigAbility extends AceAbility {

  7.     public static Long cardId;

  8.     @Override
  9.     public void onStart(Intent intent) {
  10.         setInstanceName("LevelCard");
  11.         // 获取卡片ID并进行保存
  12.         IntentParams params = intent.getParams();
  13.         cardId = (long) params.getParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY);

  14.         super.onStart(intent);
  15.     }

  16.     @Override
  17.     public void onStop() {
  18.         super.onStop();
  19.     }
  20. }
复制代码

3.创建CardServiceAbility来获取配置页面的配置信息并且更新卡片
  1. package com.example.phone.ability;

  2. import ohos.aafwk.ability.Ability;
  3. import ohos.aafwk.ability.AbilitySlice;
  4. import ohos.aafwk.ability.FormBindingData;
  5. import ohos.aafwk.ability.FormException;
  6. import ohos.aafwk.content.Intent;
  7. import ohos.aafwk.content.IntentParams;
  8. import ohos.app.Context;
  9. import ohos.rpc.*;
  10. import ohos.hiviewdfx.HiLog;
  11. import ohos.hiviewdfx.HiLogLabel;
  12. import ohos.utils.zson.ZSONObject;

  13. public class CardServiceAbility extends Ability {
  14.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");

  15.     private CardServiceAbility.CardServiceRemote cardServiceRemote;
  16.     private static final int CHOOSE_LEVEL = 1001;

  17.     @Override
  18.     public void onStart(Intent intent) {
  19.         HiLog.error(LABEL_LOG, "CardServiceAbility::onStart");
  20.         cardServiceRemote = new CardServiceRemote();
  21.         super.onStart(intent);
  22.     }

  23.     @Override
  24.     protected IRemoteObject onConnect(Intent intent) {
  25.         super.onConnect(intent);
  26.         return cardServiceRemote.asObject();
  27.     }

  28.     @Override
  29.     public void onDisconnect(Intent intent) {
  30.     }


  31.     class CardServiceRemote extends RemoteObject implements IRemoteBroker {

  32.         public CardServiceRemote() {
  33.             super("CardServiceRemote");
  34.         }

  35.         @Override
  36.         public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
  37.             switch (code) {
  38.                 case CHOOSE_LEVEL:{

  39.                     String zsonStr = data.readString();

  40.                     ZSONObject zsonObject = new ZSONObject();
  41.                     zsonObject.put("name", zsonStr+"#液位计:");
  42.                     FormBindingData formBindingData = new FormBindingData(zsonObject);
  43.                     try {
  44.                         if (!updateForm(LevelCardConfigAbility.cardId, formBindingData)) {
  45.                             // err process
  46.                         }
  47.                     } catch (FormException e) {
  48.                         e.printStackTrace();
  49.                     }

  50.                     break;
  51.                 }
  52.                 default: {
  53.                     reply.writeString("service not defined");
  54.                     return false;
  55.                 }
  56.             }
  57.             return true;
  58.         }

  59.         @Override
  60.         public IRemoteObject asObject() {
  61.             return this;
  62.         }
  63.     }
  64. }
复制代码

效果:

编辑页面详情

7.3 自定义刷新策略
7.3.1 关系型数据库加入包
1.1 在对应的entry的build.gradle中添加包
  1. dependencies {
  2.     implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
  3.     testCompile 'junit:junit:4.12'

  4.     compile files(ORM_ANNOTATIONS_JAVA, ORM_ANNOTATIONS_PROCESSOR_JAVA, JAVAPOET_JAVA)
  5.     annotationProcessor files(ORM_ANNOTATIONS_JAVA, ORM_ANNOTATIONS_PROCESSOR_JAVA, JAVAPOET_JAVA)
  6. }
复制代码


1.2 在gradle.properties中添加gradle全局变量
  1. JAVAPOET_JAVA=C:/Users/XX/AppData/Local/Huawei/Sdk/java/2.1.1.21/build-tools/lib/javapoet_java.jar
  2. ORM_ANNOTATIONS_PROCESSOR_JAVA=C:/Users/XX/AppData/Local/Huawei/Sdk/java/2.1.1.21/build-tools/lib/orm_annotations_processor_java.jar
  3. ORM_ANNOTATIONS_JAVA=C:/Users/XX/AppData/Local/Huawei/Sdk/java/2.1.1.21/build-tools/lib/orm_annotations_java.jar
复制代码

1.3 重新构建
7.3.2 创建数据库类和表类
1.数据库类
例如,定义了一个数据库类LevelStore.java,数据库包含了“Level”表,版本号为“1”。数据库类的getVersion方法和getHelper方法不需要实现,直接将数据库类设为虚类即可。
  1. package com.example.phone.store;

  2. import com.example.phone.store.from.Level;
  3. import ohos.data.orm.OrmDatabase;
  4. import ohos.data.orm.annotation.Database;

  5. @Database(entities = {Level.class}, version = 1)
  6. public abstract class LevelStore extends OrmDatabase {
  7. }
复制代码

2.创建表类
  1. package com.example.phone.store.from;

  2. import ohos.data.orm.OrmObject;
  3. import ohos.data.orm.annotation.Entity;
  4. import ohos.data.orm.annotation.PrimaryKey;

  5. @Entity(tableName = "level")
  6. public class Level extends OrmObject {

  7.     public Long getId() {
  8.         return id;
  9.     }

  10.     public void setId(Long id) {
  11.         this.id = id;
  12.     }

  13.     public String getName() {
  14.         return name;
  15.     }

  16.     public Level() {

  17.     }

  18.     public Level(Long id, String name) {
  19.         this.id = id;
  20.         this.name = name;
  21.     }

  22.     @Override
  23.     public String toString() {
  24.         return "LevelCard{" +
  25.                 "id=" + id +
  26.                 ", name='" + name + '\'' +
  27.                 '}';
  28.     }

  29.     public void setName(String name) {
  30.         this.name = name;
  31.     }

  32.     @PrimaryKey(autoGenerate = true)
  33.     private Long id;

  34.     private String name;

  35. }
复制代码

7.3.3 卡片数据将存在数据库并定时刷新
  1. private static OrmContext ormContext = null;
  2. private DatabaseHelper helper = new DatabaseHelper(this);

  3. @Override
  4. protected ProviderFormInfo onCreateForm(Intent intent) {
  5.    
  6.         IntentParams params = intent.getParams();
  7.         if (params == null) {
  8.             return null;
  9.         }
  10.         // 卡片ID
  11.         Long formId = (long) params.getParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY);
  12.         // 卡片名称
  13.         String formName = (String) params.getParam(AbilitySlice.PARAM_FORM_NAME_KEY);
  14.         // 卡片规格信息
  15.         int specificationId = (int) params.getParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY);
  16.         System.out.println( "创建卡片: " + formId + " " + formName + " " + specificationId);

  17.         if(ormContext == null){
  18.             createDataBase(getContext());
  19.         }

  20.         // 存储数据
  21.         Level newLevel = new Level(formId, formName);
  22.         boolean isSuccessed = ormContext.insert(newLevel);
  23.         isSuccessed = ormContext.flush();
  24.    

  25. }

  26. public void createDataBase(Context context){
  27.         // 创建数据库
  28.         ormContext = helper.getOrmContext("LevelStore", "LevelStore.db",     LevelStore.class);
  29.         // 启动定时刷新程序
  30.         startTimer();
  31. }

  32. private void startTimer(){
  33.         Timer timer = new Timer();
  34.         timer.schedule(new TimerTask() {
  35.             @Override
  36.             public void run() {
  37.                 // 查询数据库获取数据
  38.                 OrmPredicates query = ormContext.where(Level.class);
  39.                 List<Level> levelCard = ormContext.query(query);
  40.                 ZSONObject zsonObject = new ZSONObject();

  41.                 try {
  42.                     for (Level l:levelCard){
  43.                         Long formId = l.getId();

  44.                         // 设置数据
  45.                         double randomLevel = Math.random()*10;
  46.                         DecimalFormat randomLevelDf = new DecimalFormat( "0.00");
  47.                         zsonObject.put("level", randomLevelDf.format(randomLevel));

  48.                         FormBindingData formBindingData = new FormBindingData(zsonObject);
  49.                         if (!updateForm(formId, formBindingData)) {
  50.                             deleteLevelCard(formId);
  51.                         }
  52.                     }
  53.                 } catch (FormException e) {
  54.                     e.printStackTrace();
  55.                 }
  56.             }
  57.         },5,700L);
  58.     }
复制代码

效果展示,演示视频:


8.小卡片和硬件HI3861交互 通过创建两个线程来处理接收和发送的数据
  1. System.out.println(<span class="hljs-string">"连接设备"</span>);
  2.                     <span class="hljs-keyword">if</span>(socket == <span class="hljs-keyword">null</span>) {
  3.                         TaskDispatcher globalTaskDispatcher = <span class="hljs-keyword">null</span>;
  4.                         globalTaskDispatcher = context.getGlobalTaskDispatcher(TaskPriority.DEFAULT);
  5.                         <span class="hljs-keyword">try</span> {
  6.                             socket = <span class="hljs-keyword">new</span> Socket(<span class="hljs-string">"192.168.1.1"</span>, <span class="hljs-number">30001</span>);
  7.                             os = socket.getOutputStream();
  8.                             socket.setSoTimeout(<span class="hljs-number">3000</span>);
  9.                         } <span class="hljs-keyword">catch</span> (IOException e) {
  10.                             e.printStackTrace();
  11.                             System.out.println(<span class="hljs-string">"服务器连接失败"</span>);
  12.                             ZSONObject zsonObjectData = <span class="hljs-keyword">new</span> ZSONObject();
  13.                             zsonObjectData.put(<span class="hljs-string">"code"</span>,<span class="hljs-number">1</span>);
  14.                             zsonObjectData.put(<span class="hljs-string">"msg"</span>,<span class="hljs-string">"服务器连接失败"</span>);
  15.                             reply.writeString(zsonObjectData.toString());
  16.                             <span class="hljs-keyword">break</span>;
  17.                         }
  18.                         <span class="hljs-comment">// 接收线程</span>
  19.                         Revocable revocable = globalTaskDispatcher.asyncDispatch(<span class="hljs-keyword">new</span> Runnable() {
  20.                             <span class="hljs-annotation">@Override</span>
  21.                             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {
  22.                                 System.out.println(<span class="hljs-string">"发送线程启动"</span>);
  23.                                 <span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>){
  24.                                     <span class="hljs-keyword">if</span>(sendFlag == <span class="hljs-number">1</span>){
  25.                                         System.out.println(<span class="hljs-string">"发送数据..."</span>);
  26.                                         PrintWriter pw = <span class="hljs-keyword">new</span> PrintWriter(os);
  27.                                         pw.write(sendMsg);
  28.                                         pw.flush();
  29.                                         sendFlag = <span class="hljs-number">0</span>;
  30.                                     }
  31.                                 }
  32.                             }
  33.                         });

  34.                         <span class="hljs-comment">// 发送线程</span>
  35.                         Revocable revocable2 = globalTaskDispatcher.asyncDispatch(<span class="hljs-keyword">new</span> Runnable() {
  36.                             <span class="hljs-annotation">@Override</span>
  37.                             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {
  38.                                 System.out.println(<span class="hljs-string">"发送线程启动"</span>);
  39.                                 InputStream in = <span class="hljs-keyword">null</span>;
  40.                                 <span class="hljs-keyword">try</span> {
  41.                                     in = socket.getInputStream();
  42.                                 } <span class="hljs-keyword">catch</span> (IOException e) {
  43.                                     e.printStackTrace();
  44.                                 }
  45.                                 <span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>){
  46.                                     <span class="hljs-keyword">int</span> len;
  47.                                     <span class="hljs-keyword">byte</span>[] bytes = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];
  48.                                     <span class="hljs-keyword">try</span> {
  49.                                         <span class="hljs-keyword">while</span> ((len = in.read(bytes)) != -<span class="hljs-number">1</span>) { <span class="hljs-comment">//此函数是阻塞的</span>
  50.                                             getMsg = <span class="hljs-keyword">new</span> String(bytes,<span class="hljs-number">0</span>,len, StandardCharsets.UTF_8);
  51.                                             getFlag = <span class="hljs-number">1</span>;
  52.                                         }
  53.                                     }<span class="hljs-keyword">catch</span> (IOException e){
  54.                                         System.out.println(e.toString());
  55.                                     }
  56.                                     System.out.println(<span class="hljs-string">"Connection interruption"</span>);
  57.                                 }
  58.                             }
  59.                         });

  60.                     }
复制代码
  1.                     <span class="hljs-comment">// 发送数据</span>
  2.                     ZSONObject zdata = <span class="hljs-keyword">new</span> ZSONObject();
  3.                     zdata.put(<span class="hljs-string">"code"</span>,<span class="hljs-number">1</span>);
  4.                     sendMsg = zdata.toString();
  5.                     sendFlag = <span class="hljs-number">1</span>;

  6.                     <span class="hljs-comment">//接收数据</span>
  7.                     <span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>){
  8.                         <span class="hljs-keyword">if</span>(getFlag == <span class="hljs-number">1</span>){
  9.                             String backData = getMsg;
  10.                             ZSONObject zsonObjectData = <span class="hljs-keyword">new</span> ZSONObject();
  11.                             zsonObjectData.put(<span class="hljs-string">"code"</span>,<span class="hljs-number">0</span>);
  12.                             zsonObjectData.put(<span class="hljs-string">"adData"</span>,backData);
  13.                             reply.writeString(zsonObjectData.toString());
  14.                             getFlag = <span class="hljs-number">0</span>;
  15.                             <span class="hljs-keyword">break</span>;
  16.                         }
  17.                     }
复制代码

在CardServiceAbility中读取接收到的getMsg变量在调用updateForm函数
9.分布式卡片开发

10.哔哩哔哩弹幕姬鸿蒙版

我这里只提供思路,和逻辑,教程上面都有我就别写了
1.创建卡片数据库和卡片表
2.创建JS卡片和卡片的Ability
3.创建弹幕卡片编辑页面FA
4.创建弹幕卡片编辑PA
5.编写JS卡片


6.编写卡片编辑页面


7.配置小卡片,把编辑页面的ability加入卡片配置,修改卡片的名字等等
8.处理卡片创建
卡片创建时把ID存在卡片数据库
9.编写卡片编辑逻辑
JS获取input输入mid,点击搜索请求,获取主播信息数据,把请求返回数据设置到页面上去
https://api.bilibili.com/x/space/acc/info?mid=123456
  1. {
  2.         "<span class="hljs-attribute">code</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  3.         "<span class="hljs-attribute">message</span>": <span class="hljs-value"><span class="hljs-string">"0"</span></span>,
  4.         "<span class="hljs-attribute">ttl</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  5.         "<span class="hljs-attribute">data</span>": <span class="hljs-value">{
  6.                 "<span class="hljs-attribute">mid</span>": <span class="hljs-value"><span class="hljs-number">123456</span></span>,
  7.                 "<span class="hljs-attribute">name</span>": <span class="hljs-value"><span class="hljs-string">"哦哈哟"</span></span>,
  8.                 "<span class="hljs-attribute">sex</span>": <span class="hljs-value"><span class="hljs-string">"男"</span></span>,
  9.                 "<span class="hljs-attribute">face</span>": <span class="hljs-value"><span class="hljs-string">"http://i0.hdslb.com/bfs/face/2fa84e04217f91399fb93d7eb2716a5eee55ec78.jpg"</span></span>,
  10.                 "<span class="hljs-attribute">sign</span>": <span class="hljs-value"><span class="hljs-string">"不卖 老板我不卖"</span></span>,
  11.                 "<span class="hljs-attribute">rank</span>": <span class="hljs-value"><span class="hljs-number">10000</span></span>,
  12.                 "<span class="hljs-attribute">level</span>": <span class="hljs-value"><span class="hljs-number">5</span></span>,
  13.                 "<span class="hljs-attribute">jointime</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  14.                 "<span class="hljs-attribute">moral</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  15.                 "<span class="hljs-attribute">silence</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  16.                 "<span class="hljs-attribute">birthday</span>": <span class="hljs-value"><span class="hljs-string">"01-01"</span></span>,
  17.                 "<span class="hljs-attribute">coins</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  18.                 "<span class="hljs-attribute">fans_badge</span>": <span class="hljs-value"><span class="hljs-literal">false</span></span>,
  19.                 "<span class="hljs-attribute">official</span>": <span class="hljs-value">{
  20.                         "<span class="hljs-attribute">role</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  21.                         "<span class="hljs-attribute">title</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  22.                         "<span class="hljs-attribute">desc</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  23.                         "<span class="hljs-attribute">type</span>": <span class="hljs-value">-<span class="hljs-number">1</span>
  24.                 </span>}</span>,
  25.                 "<span class="hljs-attribute">vip</span>": <span class="hljs-value">{
  26.                         "<span class="hljs-attribute">type</span>": <span class="hljs-value"><span class="hljs-number">2</span></span>,
  27.                         "<span class="hljs-attribute">status</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  28.                         "<span class="hljs-attribute">due_date</span>": <span class="hljs-value"><span class="hljs-number">2044454400000</span></span>,
  29.                         "<span class="hljs-attribute">vip_pay_type</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  30.                         "<span class="hljs-attribute">theme_type</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  31.                         "<span class="hljs-attribute">label</span>": <span class="hljs-value">{
  32.                                 "<span class="hljs-attribute">path</span>": <span class="hljs-value"><span class="hljs-string">"http://i0.hdslb.com/bfs/vip/label_annual.png"</span></span>,
  33.                                 "<span class="hljs-attribute">text</span>": <span class="hljs-value"><span class="hljs-string">"十年大会员"</span></span>,
  34.                                 "<span class="hljs-attribute">label_theme</span>": <span class="hljs-value"><span class="hljs-string">"ten_annual_vip"</span></span>,
  35.                                 "<span class="hljs-attribute">text_color</span>": <span class="hljs-value"><span class="hljs-string">"#FFFFFF"</span></span>,
  36.                                 "<span class="hljs-attribute">bg_style</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  37.                                 "<span class="hljs-attribute">bg_color</span>": <span class="hljs-value"><span class="hljs-string">"#FB7299"</span></span>,
  38.                                 "<span class="hljs-attribute">border_color</span>": <span class="hljs-value"><span class="hljs-string">""</span>
  39.                         </span>}</span>,
  40.                         "<span class="hljs-attribute">avatar_subscript</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  41.                         "<span class="hljs-attribute">nickname_color</span>": <span class="hljs-value"><span class="hljs-string">"#FB7299"</span></span>,
  42.                         "<span class="hljs-attribute">role</span>": <span class="hljs-value"><span class="hljs-number">7</span></span>,
  43.                         "<span class="hljs-attribute">avatar_subscript_url</span>": <span class="hljs-value"><span class="hljs-string">"http://i0.hdslb.com/bfs/vip/icon_Certification_big_member_22_3x.png"</span>
  44.                 </span>}</span>,
  45.                 "<span class="hljs-attribute">pendant</span>": <span class="hljs-value">{
  46.                         "<span class="hljs-attribute">pid</span>": <span class="hljs-value"><span class="hljs-number">462</span></span>,
  47.                         "<span class="hljs-attribute">name</span>": <span class="hljs-value"><span class="hljs-string">"地中海"</span></span>,
  48.                         "<span class="hljs-attribute">image</span>": <span class="hljs-value"><span class="hljs-string">"http://i0.hdslb.com/bfs/face/c8735da69314d54144a0b1fde5d69676ce72d7b6.png"</span></span>,
  49.                         "<span class="hljs-attribute">expire</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  50.                         "<span class="hljs-attribute">image_enhance</span>": <span class="hljs-value"><span class="hljs-string">"http://i0.hdslb.com/bfs/face/c8735da69314d54144a0b1fde5d69676ce72d7b6.png"</span></span>,
  51.                         "<span class="hljs-attribute">image_enhance_frame</span>": <span class="hljs-value"><span class="hljs-string">""</span>
  52.                 </span>}</span>,
  53.                 "<span class="hljs-attribute">nameplate</span>": <span class="hljs-value">{
  54.                         "<span class="hljs-attribute">nid</span>": <span class="hljs-value"><span class="hljs-number">88</span></span>,
  55.                         "<span class="hljs-attribute">name</span>": <span class="hljs-value"><span class="hljs-string">"十年大会员"</span></span>,
  56.                         "<span class="hljs-attribute">image</span>": <span class="hljs-value"><span class="hljs-string">"http://i1.hdslb.com/bfs/face/5b04cc2fb1c479874cac145eb7ac7098a1e081d9.png"</span></span>,
  57.                         "<span class="hljs-attribute">image_small</span>": <span class="hljs-value"><span class="hljs-string">"http://i2.hdslb.com/bfs/face/b44b390de6b68a9ac7087b3bef07ad90a46101c4.png"</span></span>,
  58.                         "<span class="hljs-attribute">level</span>": <span class="hljs-value"><span class="hljs-string">"稀有勋章"</span></span>,
  59.                         "<span class="hljs-attribute">condition</span>": <span class="hljs-value"><span class="hljs-string">"累计开通大会员总时长\u003e=10年即可获得"</span>
  60.                 </span>}</span>,
  61.                 "<span class="hljs-attribute">user_honour_info</span>": <span class="hljs-value">{
  62.                         "<span class="hljs-attribute">mid</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  63.                         "<span class="hljs-attribute">colour</span>": <span class="hljs-value"><span class="hljs-literal">null</span></span>,
  64.                         "<span class="hljs-attribute">tags</span>": <span class="hljs-value"><span class="hljs-literal">null</span>
  65.                 </span>}</span>,
  66.                 "<span class="hljs-attribute">is_followed</span>": <span class="hljs-value"><span class="hljs-literal">false</span></span>,
  67.                 "<span class="hljs-attribute">top_photo</span>": <span class="hljs-value"><span class="hljs-string">"http://i2.hdslb.com/bfs/space/cb1c3ef50e22b6096fde67febe863494caefebad.png"</span></span>,
  68.                 "<span class="hljs-attribute">theme</span>": <span class="hljs-value">{}</span>,
  69.                 "<span class="hljs-attribute">sys_notice</span>": <span class="hljs-value">{}</span>,
  70.                 "<span class="hljs-attribute">live_room</span>": <span class="hljs-value">{
  71.                         "<span class="hljs-attribute">roomStatus</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  72.                         "<span class="hljs-attribute">liveStatus</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  73.                         "<span class="hljs-attribute">url</span>": <span class="hljs-value"><span class="hljs-string">"https://live.bilibili.com/5052841"</span></span>,
  74.                         "<span class="hljs-attribute">title</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  75.                         "<span class="hljs-attribute">cover</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  76.                         "<span class="hljs-attribute">online</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  77.                         "<span class="hljs-attribute">roomid</span>": <span class="hljs-value"><span class="hljs-number">5052841</span></span>,
  78.                         "<span class="hljs-attribute">roundStatus</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  79.                         "<span class="hljs-attribute">broadcast_type</span>": <span class="hljs-value"><span class="hljs-number">0</span>
  80.                 </span>}
  81.         </span>}
  82. </span>}
复制代码
点击确认调用弹幕卡片编辑PA,把请求返回数据整理后发给PA,在PA中把主播信息数据存到对应卡片的数据库中
10.定时更新逻辑
从数据库中读取卡片列表设置数据,在项目中添加okhttp包
implementation 'com.squareup.okhttp3:okhttp:4.4.0'在定时更新逻辑中请求获取直播间弹幕,其中roomid是从编辑页面获取到的主播信息数据中拿到的
https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23208586
  1. {
  2.         "<span class="hljs-attribute">code</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  3.         "<span class="hljs-attribute">data</span>": <span class="hljs-value">{
  4.                 "<span class="hljs-attribute">admin</span>": <span class="hljs-value">[{
  5.                         "<span class="hljs-attribute">text</span>": <span class="hljs-value"><span class="hljs-string">"白白"</span></span>,
  6.                         "<span class="hljs-attribute">uid</span>": <span class="hljs-value"><span class="hljs-number">454613875</span></span>,
  7.                         "<span class="hljs-attribute">nickname</span>": <span class="hljs-value"><span class="hljs-string">"昆士兰村民"</span></span>,
  8.                         "<span class="hljs-attribute">uname_color</span>": <span class="hljs-value"><span class="hljs-string">"#00D1F1"</span></span>,
  9.                         "<span class="hljs-attribute">timeline</span>": <span class="hljs-value"><span class="hljs-string">"2021-06-27 20:10:51"</span></span>,
  10.                         "<span class="hljs-attribute">isadmin</span>": <span class="hljs-value"><span class="hljs-number">1</span></span>,
  11.                         "<span class="hljs-attribute">vip</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  12.                         "<span class="hljs-attribute">svip</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  13.                         "<span class="hljs-attribute">medal</span>": <span class="hljs-value">[<span class="hljs-number">22</span>, <span class="hljs-string">"鬼来了"</span>, <span class="hljs-string">"2999狼外婆"</span>, <span class="hljs-number">23208586</span>, <span class="hljs-number">1725515</span>, <span class="hljs-string">""</span>, <span class="hljs-number">0</span>, <span class="hljs-number">6809855</span>, <span class="hljs-number">1725515</span>, <span class="hljs-number">5414290</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">71598153</span>]</span>,
  14.                         "<span class="hljs-attribute">title</span>": <span class="hljs-value">[<span class="hljs-string">""</span>, <span class="hljs-string">""</span>]</span>,
  15.                         "<span class="hljs-attribute">user_level</span>": <span class="hljs-value">[<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">9868950</span>, <span class="hljs-string">"\u003e50000"</span>]</span>,
  16.                         "<span class="hljs-attribute">rank</span>": <span class="hljs-value"><span class="hljs-number">10000</span></span>,
  17.                         "<span class="hljs-attribute">teamid</span>": <span class="hljs-value"><span class="hljs-number">0</span></span>,
  18.                         "<span class="hljs-attribute">rnd</span>": <span class="hljs-value"><span class="hljs-string">"537003298"</span></span>,
  19.                         "<span class="hljs-attribute">user_title</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  20.                         "<span class="hljs-attribute">guard_level</span>": <span class="hljs-value"><span class="hljs-number">3</span></span>,
  21.                         "<span class="hljs-attribute">bubble</span>": <span class="hljs-value"><span class="hljs-number">5</span></span>,
  22.                         "<span class="hljs-attribute">bubble_color</span>": <span class="hljs-value"><span class="hljs-string">"#1453BAFF,#4C2263A2,#3353BAFF"</span></span>,
  23.                         "<span class="hljs-attribute">check_info</span>": <span class="hljs-value">{
  24.                                 "<span class="hljs-attribute">ts</span>": <span class="hljs-value"><span class="hljs-number">1624795851</span></span>,
  25.                                 "<span class="hljs-attribute">ct</span>": <span class="hljs-value"><span class="hljs-string">"1BF7F361"</span>
  26.                         </span>}</span>,
  27.                         "<span class="hljs-attribute">lpl</span>": <span class="hljs-value"><span class="hljs-number">0</span>
  28.                 </span>}]
  29.         </span>}</span>,
  30.         "<span class="hljs-attribute">message</span>": <span class="hljs-value"><span class="hljs-string">""</span></span>,
  31.         "<span class="hljs-attribute">msg</span>": <span class="hljs-value"><span class="hljs-string">""</span>
  32. </span>}
复制代码

效果视频:哔哩哔哩弹幕姬鸿蒙版

短短 2021-6-28 15:38:42
真不错!期待完整连载内容~
回复

举报

挽你何用 2021-8-17 13:53:10
这文章太棒了,大佬⑥皮
回复

举报

评论

您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发文章
快速回复
扫一扫分享
返回顶部 返回列表