2021-09-03 17:14:12
0
1. 介绍 分布式手写板利用分布式数据库和分布式设备启动与连接实现。每台设备在书写的时候,连接的多台设备都能实时同步笔迹。为了让您快速了解本篇Codelab所实现的功能,我们先对分布式手写板进行展示,效果图如下:
图1 设备拉起界面
设备选择弹框,点击设备图标(可以多选)勾选完成,点击确认按钮可拉起设备。
图2 图形绘制界面
图中拉起三台设备,从左到右第一台设备书写笔迹是黑色,第二台设备书写笔迹是蓝色,第三台书写笔迹是红色(每台设备的画笔初始化时都会随机一种颜色),每台设备笔迹都会同步到连接的设备上显示。
图3 分布式手写板演示图
2. 搭建HarmonyOS环境 我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
- 安装DevEco Studio,详情请参考下载和安装软件。
- 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
- 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
- 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
- 开发者可以参考以下链接,完成设备调试的相关配置:
您可以利用如下设备完成Codelab:开启了开发者模式的HarmonyOS真机或DevEco Studio自带模拟器。
说明
本篇文章使用的DevEco Studio版本为DevEco Studio 2.1 Beta4,使用的SDK版本为API Version 5。
3. 代码结构解读
本篇Codelab只是对核心代码进行讲解,可以在后面章节中下载完整代码,以下介绍整个工程的代码结构。
- bean:DeviceData设备适配器实体类;MyPoint存放绘制点的坐标和基本信息。
- listcomponent:根据每个设备处理每个设备组件。
- component:DeviceSelectDialog展示设备列表对话框,用户选择设备(可以是多个设备)进行连接;DrawPoint存放所有绘制点的基本信息和绘图。
- slice:MainAbilitySlice画板的主界面。
- utils:LogUtil主要作用打印日志信息;GsonUtils用于将绘制的多个点转成字符串。
- resources:存放工程使用到的资源文件,其中resourcesbaselayout下存放xml布局文件,resourcesbasemedia下存放图片资源。
- config.json:应用的配置文件。
4. 相关权限 本程序开发需要申请以下多设备协同相关的四个权限,应用权限的申请可以参考权限章节。
权限名
| 说明
|
ohos.permission.DISTRIBUTED_DATASYNC
| 必选(分布式数据管理权限,允许不同设备间的数据交换)
|
ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE
| 必选(允许获取分布式组网内设备的状态变化)
|
ohos.permission.GET_DISTRIBUTED_DEVICE_INFO
| 必选(允许获取分布式组网内的设备列表和设备信息)
|
ohos.permission.GET_BUNDLE_INFO
| 必选(查询其他应用信息的权限)
|
说明
其中多设备协同数据同步权限"ohos.permission.DISTRIBUTED_DATASYNC",需要按照动态申请流程向用户申请授权。
5. 设备连接
6. 画笔连线实现
主要遍历所有点,判断该点是否为最后一个点,如果不是,借助Canvas将这个点与之前的点连接组成线条,如果是,跳过本次循环继续下次循环,也就是一条线的完成,实现代码如下:
- private void draw(List<MyPoint> points, Canvas canvas) {
- if (points != null && points.size() > 1) {
- Point first = null;
- Point last = null;
- for (MyPoint myPoint : points) {
- paint.setColor(myPoint.getPaintColor());
- float finalX = myPoint.getPositionX();
- float finalY = myPoint.getPositionY();
- Point finalPoint = new Point(finalX, finalY);
- if (myPoint.isLastPoint()) {
- first = null;
- last = null;
- continue;
- }
- if (first == null) {
- first = finalPoint;
- } else {
- if (last != null) {
- first = last;
- }
- last = finalPoint;
- canvas.drawLine(first, last, paint);
- }
- }
- }
- }
复制代码
7. 分布式数据服务
分布式数据库有专门的文档讲解,详细讲解请参照文档,这里仅对关键代码供参考,代码如下:
- private void initDatabase() {
- // 创建分布式数据库管理对象
- KvManagerConfig config = new KvManagerConfig(this);
- kvManager = KvManagerFactory.getInstance().createKvManager(config);
- // 创建分布式数据库
- Options options = new Options();
- options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION);
- singleKvStore = kvManager.getKvStore(options, STORE_ID);
- // 订阅分布式数据变化
- KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient();
- singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, kvStoreObserverClient);
- }
复制代码
8. 数据存储写入
在setTouchEventListener监听事件开始时加入定时任务scheduledTask(),每200ms往数据库写一次数据(这个time常量可根据需求自定义),当TouchEvent.PRIMARY_POINT_UP事件触发,也就是最后一跟手指离开屏幕时取消定时任务,代码如下:
- private static final int TIME = 200;
- private static final int EVENT_MSG_STORE = 0x1000002;
-
- private EventHandler handler = new EventHandler(EventRunner.current()) {
- @Override
- protected void processEvent(InnerEvent event) {
- switch (event.eventId) {
- case EVENT_MSG_STORE:
- callBack.callBack(points);
- break;
- default:
- break;
- }
- }
- };
-
- private void init(int colorIndex) {
- paint = new Paint();
- paint.setAntiAlias(true);
- paint.setStyle(Paint.Style.STROKE_STYLE);
- paint.setStrokeWidth(STROKE_WIDTH);
- addDrawTask(this);
- Color color = getRandomColor(colorIndex);
-
- setTouchEventListener((component, touchEvent) -> {
- scheduledTask();
- int crtX = (int) touchEvent.getPointerPosition(touchEvent.getIndex()).getX();
- int crtY = (int) touchEvent.getPointerPosition(touchEvent.getIndex()).getY()-150;
-
- MyPoint point = new MyPoint(crtX, crtY);
- point.setPaintColor(color);
-
- switch (touchEvent.getAction()) {
- case TouchEvent.POINT_MOVE:
- points.add(point);
- break;
- case TouchEvent.PRIMARY_POINT_UP:
- points.add(point);
- point.setLastPoint(true);
- callBack.callBack(points);
- onTimerFinish();
- break;
- }
- invalidate();
- return true;
- });
- }
-
- public void scheduledTask(){
- if (timer == null && timerTask == null) {
- timer = new Timer();
- timerTask = new TimerTask() {
- @Override
- public void run() {
- handler.sendEvent(EVENT_MSG_STORE);
- }
- };
- timer.schedule(timerTask, 0, TIME);
- }
- }
-
- public void onTimerFinish() {
- timer.cancel();
- timer = null;
- timerTask = null;
- }
复制代码
9. 笔迹撤回
每个MyPoint都有一个属性isLastPoint用于标记此点是否为最后一个点,首先移除第一个isLastPoint=true的点,然后从后往前遍所有点,移除isLastPoin()=false直到遇到isLastPoint=true跳出循环,存入新数据,更新数据服务,就可实现同步撤回功能,代码如下:
- back.setClickedListener(component -> {
- List<MyPoint> points = drawl.getPoints();
- if (points != null && points.size() > 1) {
- points.remove(points.size() - 1);
- for (int i = points.size() - 1; i >= 0; i--) {
- MyPoint mypoint = points.get(i);
- if (mypoint.isLastPoint()) break;
- points.remove(i);
- }
- drawl.setDrawParams(points);
- String pointsString = GsonUtil.objectToString(points);
- LogUtils.info(TAG, "pointsString::" + pointsString);
- if (singleKvStore != null) {
- singleKvStore.putString("points", pointsString);
- }
- }
- });
复制代码
10. 画笔颜色
通过intent传值,为每台设备编号,每个数字对应paintColors数组的index,实现每台设备一种颜色(只定义了三种颜色),多的设备定义成红色,关键代码如下:
- intent.setParam("colorIndex",i+1);
-
- private Color[] paintColors = new Color[]{Color.RED, Color.BLUE, Color.BLACK};
-
- private Color getRandomColor(int n) {
- return n>paintColors.length-1 ? paintColors[0]: paintColors[n];
- }
复制代码
11. 恭喜你
通过本教程的学习,你已经学会了HarmonyOS分布式数据库和分布式设备启动与连接,利用canvas组件绘制图形。
12. 参考
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。
侵权投诉