【ArkUI进阶练中学】第9课:分布式能力与多设备协同

本节目标

  • 理解HarmonyOS分布式技术的整体架构分层,掌握分布式软总线、设备管理、数据管理等核心组件的定位与协作关系
  • 掌握distributedDeviceManager的设备发现、认证与状态监听能力,能够实现跨设备设备发现与选择
  • 掌握分布式数据对象distributedDataObject的创建、会话加入与数据同步机制,能够实现多设备间的实时数据同步
  • 掌握分布式键值型数据库的同步方式,理解单版本数据库与多设备协同数据库的选型边界
  • 掌握应用接续的开发流程,能够通过onContinue和onCreate实现跨设备任务迁移
  • 掌握一次开发多端部署的断点系统与三层工程架构,能够实现响应式布局适配
  • 能够为分布式应用设计合理的状态同步与冲突处理方案

一、分布式技术架构概述

1.1 分布式软总线

分布式软总线是HarmonyOS分布式能力的通信基座,为设备之间的互联互通提供了统一的分布式通信能力。它通过统一的通信协议,让不同类型的鸿蒙设备(如手机、平板、智慧屏/电视)无需复杂配网即可自动发现、连接并协同工作,实现设备内和设备间高吞吐、低时延、高可靠的流畅连接体验。对开发者而言,无需关注组网方式与通信协议,只需通过上层API即可完成跨设备通信。

核心特性:

  • 设备发现:基于CoAP协议实现近场设备自动发现,支持同一局域网内设备的自动识别
  • 设备认证:基于华为账号和设备证书实现可信设备认证,保证通信安全
  • 数据传输:提供不区分链路的设备发现和传输接口,支持高效分发任务和传输数据

关键约束 :分布式软总线本身是"尽力而为"的,保证传输可靠性但不保证传输稳定性,不提供内置的持久化任务队列或自动重试机制 。开发者需要通过监听设备上下线状态(on('deviceStateChange'))来实现自定义的容错恢复逻辑。

1.2 设备管理

@ohos.distributedDeviceManager模块提供分布式设备管理能力,是分布式能力的"设备管家"。它负责设备的注册、发现、状态管理和服务发布,应用可调用接口实现注册和解除注册设备上下线变化监听、发现周边不可信设备、认证和取消认证设备、查询可信设备列表、查询本地设备信息等功能。如果把分布式软总线比作"通信管道",那DeviceManager就是管道上的"调度中心",决定哪些设备可以接入、哪些服务可以被发现。

1.3 自由流转

在HarmonyOS中,将跨多设备的分布式操作统称为流转 ;根据使用场景的不同,流转又分为跨端迁移 和多端协同两种具体场景。

跨端迁移:在用户使用设备的过程中,当使用情境发生变化时,之前使用的设备可能已经不适合继续当前的任务,此时用户可以选择新的设备来继续当前的任务,原设备可按需决定是否退出任务。典型场景如平板上播放的视频迁移到智慧屏继续播放。

多端协同:用户拥有的多个设备作为一个整体,为用户提供比单设备更加高效、沉浸的体验。典型场景如两台设备打开备忘录同一篇笔记,设备A插入图片资源,设备B编辑文字内容。

自由流转底层依托分布式软总线,解决设备发现、连接、组网等痛点,对外提供硬件、数据、应用三个维度的跨设备访问能力,应用开发只需遵循框架并适配应用层API,就能实现设备之间的跨端迁移和多端协同。

二、分布式设备管理

2.1 创建设备管理实例

使用distributedDeviceManager需要先从@kit.DistributedServiceKit导入:

typescript 复制代码
import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';

let dmInstance: distributedDeviceManager.DeviceManager | null = null;

try {
  dmInstance = distributedDeviceManager.createDeviceManager('com.example.myapp');
} catch (err) {
  const e = err as BusinessError;
  console.error(`createDeviceManager errCode: ${e.code}, errMessage: ${e.message}`);
}

createDeviceManager的参数为应用的Bundle名称,长度范围1~255字符。设备管理实例不再使用后,需要通过releaseDeviceManager释放。

2.2 设备发现与认证

发现周边不可信设备并获取设备列表:

typescript 复制代码
// 获取可信设备列表
function getTrustedDevices(): Array<distributedDeviceManager.DeviceBasicInfo> {
  if (!dmInstance) return [];
  const deviceList = dmInstance.getAvailableDeviceListSync();
  deviceList.forEach((device: distributedDeviceManager.DeviceBasicInfo) => {
    console.info(`设备名称: ${device.deviceName}, 设备类型: ${device.deviceType}`);
  });
  return deviceList;
}

// 注册设备上下线监听
function setupDeviceStateListener(): void {
  if (!dmInstance) return;
  dmInstance.on('deviceStateChange', (data: {
    action: distributedDeviceManager.DeviceStateChange;
    device: distributedDeviceManager.DeviceBasicInfo;
  }) => {
    console.info(`设备状态变化: action=${data.action}, device=${data.device.deviceName}`);
    // 根据状态变化更新UI
  });
}

// 取消监听
function removeDeviceStateListener(): void {
  if (!dmInstance) return;
  dmInstance.off('deviceStateChange');
}

2.3 设备选择完整流程

在实际应用中,通常需要先发现可用设备,让用户选择目标设备后执行跨设备操作:

typescript 复制代码
@Entry
@Component
struct DeviceSelector {
  @State deviceList: Array<distributedDeviceManager.DeviceBasicInfo> = [];
  @State selectedNetworkId: string = '';

  aboutToAppear(): void {
    this.loadDevices();
  }

  loadDevices(): void {
    const dmInstance = distributedDeviceManager.createDeviceManager('com.example.myapp');
    this.deviceList = dmInstance.getAvailableDeviceListSync();
  }

  build() {
    Column({ space: 12 }) {
      Text('选择目标设备').fontSize(18).fontWeight(FontWeight.Bold)
      ForEach(this.deviceList, (device: distributedDeviceManager.DeviceBasicInfo) => {
        Row() {
          Column({ space: 4 }) {
            Text(device.deviceName).fontSize(16)
            Text(device.deviceType).fontSize(12).fontColor('#999')
          }
          .alignItems(HorizontalAlign.Start)
          .layoutWeight(1)
          if (this.selectedNetworkId === device.networkId) {
            Text('✓').fontColor('#007DFF').fontSize(18)
          }
        }
        .width('100%')
        .padding(12)
        .backgroundColor(this.selectedNetworkId === device.networkId ? '#E8F0FE' : Color.White)
        .borderRadius(8)
        .onClick(() => {
          this.selectedNetworkId = device.networkId;
        })
      }, (device: distributedDeviceManager.DeviceBasicInfo) => device.networkId)
    }
    .width('100%')
    .padding(16)
  }
}

三、分布式数据对象跨设备同步

3.1 核心概念

分布式数据对象(distributedDataObject)实现了对"变量"的"全局"访问。传统方式下,设备之间的数据同步需要开发者完成建立通信链接、消息收发处理、错误重试、数据冲突解决等操作,工作量非常大。分布式数据对象将设备之间的状态、消息发送进度、发送的数据等封装为"变量",不同设备上的应用可以像操作本地变量一样访问这些变量,系统自动完成数据的跨设备同步。

分布式数据对象的生命周期包括三种状态:未初始化 (未实例化或已被销毁)、本地数据对象 (已创建数据表但无法同步)、分布式数据对象(已创建数据表、设备在线且组网内设置同样sessionId的对象数≥2,可以跨设备同步数据)。若设备掉线或将sessionId置为空,分布式数据对象退化为本地数据对象。

3.2 创建与同步

使用分布式数据对象需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,该权限为user_grant,需要向用户弹窗申请授权。进行跨设备数据同步的设备需要登录相同的华为账号。

以下示例展示了一个跨设备待办事项同步的完整实现:

typescript 复制代码
import { distributedDataObject } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';

// 定义同步数据模型
interface TodoSyncData {
  title: string;
  isCompleted: boolean;
  lastModified: number;
}

@Entry
@Component
struct DistributedTodoPage {
  private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  private dataObject: distributedDataObject.DataObject | null = null;
  @State todoTitle: string = '';
  @State isCompleted: boolean = false;
  @State syncStatus: string = '本地模式';

  aboutToAppear(): void {
    // 创建分布式数据对象
    this.dataObject = distributedDataObject.create(this.context, {
      title: '',
      isCompleted: false,
      lastModified: 0
    } as TodoSyncData);

    // 监听远端数据变更
    this.dataObject.on('dataChange', distributedDataObject.DataObjectChangeType.change, () => {
      if (this.dataObject) {
        this.todoTitle = this.dataObject['title'] as string;
        this.isCompleted = this.dataObject['isCompleted'] as boolean;
      }
    });

    // 监听状态变化(设备上下线)
    this.dataObject.on('status', (sessionId: string, networkIds: string[]) => {
      this.syncStatus = networkIds.length >= 2 ? '已同步' : '等待设备';
    });

    // 加入同步会话
    this.dataObject.setSessionId('todo_sync_session_001');
  }

  aboutToDisappear(): void {
    if (this.dataObject) {
      this.dataObject.setSessionId('');
      this.dataObject = null;
    }
  }

  updateTodo(title: string, completed: boolean): void {
    if (!this.dataObject) return;
    this.dataObject['title'] = title;
    this.dataObject['isCompleted'] = completed;
    this.dataObject['lastModified'] = Date.now();
  }

  build() {
    Column({ space: 16 }) {
      Row() {
        Text('同步状态: ').fontSize(14)
        Text(this.syncStatus).fontSize(14)
          .fontColor(this.syncStatus === '已同步' ? '#34C759' : '#FF9500')
      }

      TextInput({ placeholder: '输入待办标题', text: this.todoTitle })
        .width('100%')
        .onChange((value: string) => {
          this.todoTitle = value;
          this.updateTodo(value, this.isCompleted);
        })

      Row({ space: 8 }) {
        Text('已完成').fontSize(14)
        Toggle({ type: ToggleType.Switch, isOn: this.isCompleted })
          .onChange((isOn: boolean) => {
            this.isCompleted = isOn;
            this.updateTodo(this.todoTitle, isOn);
          })
      }
    }
    .width('100%')
    .padding(16)
  }
}

关键规则 :不同设备上的分布式数据对象,通过设置相同的sessionId建立同步关系。一个同步关系中,一个设备只能有一个对象加入。若设备A的"分布式数据对象1"已经加入了session1,则设备A的"分布式数据对象2"无法再加入session1。

3.3 数据冲突处理

分布式数据对象默认采用后写覆盖先写(Last Write Wins, LWW) 的冲突解决策略,系统不提供自定义冲突策略接口。避免冲突的方法是在应用层自己加版本号或时间戳,同步后比对,按业务规则合并。

typescript 复制代码
// 带版本号的同步数据模型
interface VersionedSyncData {
  value: string;
  version: number;     // 版本号,每次修改递增
  deviceId: string;    // 最后修改的设备ID
  timestamp: number;   // 修改时间戳
}

function resolveConflict(local: VersionedSyncData, remote: VersionedSyncData): VersionedSyncData {
  // 优先比较版本号,版本号相同则比较时间戳
  if (local.version !== remote.version) {
    return local.version > remote.version ? local : remote;
  }
  return local.timestamp > remote.timestamp ? local : remote;
}

3.4 键值型数据库同步

除分布式数据对象外,分布式键值型数据库(DistributedKVStore)也是常用的跨设备数据同步方案。键值型数据库适合不涉及过多数据关系和业务关系的业务数据存储,比SQL数据库存储拥有更好的读写性能,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度。

单版本数据库:数据在本地以单个条目为单位保存,多个设备全局只保留一份数据,多个设备的相同记录按时间最新保留一条,设备之间修改相同的key会覆盖。常用于联系人、天气等应用存储场景。

多设备协同数据库:对Key前面拼接了本设备的DeviceID标识符,保证每个设备产生的数据严格隔离,数据以设备的维度管理,不存在冲突。常用于图库缩略图存储场景。

同步方式 :键值型数据库支持手动同步 (应用调用sync接口触发,支持PULL_ONLY、PUSH_ONLY、PUSH_PULL三种模式)和自动同步(在跨设备Call调用场景中,应用更新数据后系统自动完成同步)。

四、应用接续与跨端迁移

4.1 应用接续概述

应用接续是指用户在一个设备上操作某个应用时,可以快速切换到另一个设备的相同应用,无缝衔接之前的应用体验。例如在手机上编辑备忘录,到办公室后切换到电脑上继续编辑,完成任务的无缝衔接。

约束限制:双端设备需要登录同一华为账号;双端设备需要打开WLAN和蓝牙开关,或者在设置中的"多设备协同 > 高级"中启用"多设备协同增强服务"功能;双端设备需要在"设置"应用中开启"多设备协同 > 接续"功能;双端设备都需要安装该应用。

自API 12起,无需申请ohos.permission.DISTRIBUTED_DATASYNC权限。在onContinue回调中使用wantParam传输的数据需要控制在100KB以下,大数据量应使用分布式对象迁移数据。

4.2 开发流程

第一步:配置接续能力

在module.json5文件中,将承载页面的UIAbility配置为continuable: true:

json5 复制代码
{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "continuable": true
      }
    ]
  }
}

第二步:源端保存迁移数据

在源端UIAbility的onContinue接口中使用create接口创建分布式数据对象,将所要迁移的数据填充到分布式数据对象中:

typescript 复制代码
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { distributedDataObject } from '@kit.ArkData';

export default class EntryAbility extends UIAbility {
  onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
    // 方式一:通过wantParam传递少量数据(100KB以下)
    wantParam['pageRoute'] = 'TodoDetail';
    wantParam['todoId'] = 1001;
    wantParam['scrollOffset'] = 320;

    // 方式二:通过分布式数据对象迁移大数据量
    const syncData = distributedDataObject.create(this.context, {
      todoList: JSON.stringify(this.getTodoList()),
      lastSyncTime: Date.now()
    });
    syncData.setSessionId('continue_session_' + Date.now());

    return AbilityConstant.OnContinueResult.AGREE;
  }

  private getTodoList(): Array<object> {
    // 获取当前待办列表数据
    return [];
  }
}

第三步:目的端恢复迁移数据

在目的端的onCreate或onNewWant接口中恢复迁移数据:

typescript 复制代码
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // 恢复迁移数据
      const pageRoute = want.parameters?.['pageRoute'] as string;
      const todoId = want.parameters?.['todoId'] as number;
      const scrollOffset = want.parameters?.['scrollOffset'] as number;

      console.info(`恢复接续: page=${pageRoute}, todoId=${todoId}, offset=${scrollOffset}`);

      // 根据恢复的路由跳转到对应页面
      if (pageRoute === 'TodoDetail') {
        // 跳转到详情页并恢复滚动位置
      }
    }
  }
}

4.3 接续场景设计建议

不同类型的应用建议的接续配置项不同。工具类应用(如备忘录)通常从详情页发起接续,同步浏览进度,接续完成后源端应用退出。笔记类应用从编辑页发起接续,同步编辑进度。媒体类应用从播放页发起接续,同步播放位置。应用接续一般用于用户长时间停留的页面,默认情况下,应用接续完成后,源端应用会自动退出。

五、一次开发多端部署

5.1 三层工程架构

为便于模块管理和清晰查看模块间的依赖关系,推荐采用common、features、products三层工程结构:

products(产品定制层) :不同设备形态的product按需集成了本设备所需的特性,并进行产品化的定制。各个product各自编译为一个Entry类型的HAP包。product层向下依赖features层和common层,各product间不可相互依赖。

features(基础特性层) :抽象应用基础特性,每个特性高内聚、低耦合。需要单独部署的feature通常编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层可以横向调用及依赖common层,同时可以被products层不同设备形态的HAP所依赖,但是不能反向依赖products层。

common(公共能力层) :基础特性层依赖的公共能力,如UI组件、工具类,编译为HAR包或HSP包。

5.2 断点系统

响应式布局的核心思想是页面能够根据不同窗口或屏幕尺寸自动调整布局。系统侧将窗口宽度划分为不同的范围(称为断点),当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。

横向断点以应用窗口宽度为判断条件,推荐按照不同的阈值分成5个区间:

断点名称 窗口宽度(vp)
xs (0, 320)
sm [320, 600)
md [600, 840)
lg [840, 1440)
xl [1440, +∞)

纵向断点以应用窗口的高宽比为判断条件,推荐按照不同的阈值分成3个区间:

断点名称 高宽比
sm (0, 0.8)
md [0.8, 1.2)
lg [1.2, +∞)

一多的断点面向窗口而非面向设备类型,处于相同断点区间的窗口本质上形态相同,推荐展示相同的页面布局。同一设备上的不同窗口形态(例如全屏显示、分屏显示、自由窗口等),可能会落入不同的断点区间,展示不同断点对应的页面布局。

5.3 响应式布局实现

使用window.on('windowSizeChange')监听窗口尺寸变化,结合断点系统实现响应式布局:

typescript 复制代码
import { window } from '@kit.ArkUI';
import { mediaquery } from '@kit.ArkUI';

@Entry
@Component
struct ResponsiveLayout {
  @State currentBreakpoint: string = 'sm';
  @State currentLayout: string = '单栏';
  private windowListener: (() => void) | null = null;

  aboutToAppear(): void {
    // 方式一:使用mediaquery监听
    const listener = mediaquery.matchMediaSync('(width>=840vp)');
    listener.on('change', (result: mediaquery.MediaQueryResult) => {
      if (result.matches) {
        this.currentBreakpoint = 'lg';
        this.currentLayout = '三栏';
      } else {
        this.currentBreakpoint = 'sm';
        this.currentLayout = '单栏';
      }
    });

    // 方式二:使用window.on监听
    const win = window.getLastWindow(this.getUIContext().getHostContext());
    win.then((windowClass) => {
      windowClass.on('windowSizeChange', (size: window.Size) => {
        const widthVp = px2vp(size.width);
        if (widthVp < 320) {
          this.currentBreakpoint = 'xs';
        } else if (widthVp < 600) {
          this.currentBreakpoint = 'sm';
        } else if (widthVp < 840) {
          this.currentBreakpoint = 'md';
        } else if (widthVp < 1440) {
          this.currentBreakpoint = 'lg';
        } else {
          this.currentBreakpoint = 'xl';
        }
      });
    });
  }

  build() {
    Column() {
      Text(`当前断点: ${this.currentBreakpoint} (${this.currentLayout})`)
        .fontSize(16)
        .margin({ bottom: 16 })

      if (this.currentBreakpoint === 'lg' || this.currentBreakpoint === 'xl') {
        // 大屏:三栏布局
        Row() {
          this.sidePanel()
          this.mainContent()
          this.detailPanel()
        }
        .width('100%')
      } else if (this.currentBreakpoint === 'md') {
        // 中屏:双栏布局
        Row() {
          this.sidePanel()
          this.mainContent()
        }
        .width('100%')
      } else {
        // 小屏:单栏布局
        this.mainContent()
      }
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  sidePanel() {
    Column().width(240).height('100%').backgroundColor('#F5F7FA')
  }

  @Builder
  mainContent() {
    Column().layoutWeight(1).height('100%').backgroundColor(Color.White)
  }

  @Builder
  detailPanel() {
    Column().width(320).height('100%').backgroundColor('#F0F5FF')
  }
}

5.4 容器断点组件

从API 26开始,ArkUI提供了ContainerReader容器断点组件,用于在动态场景下根据容器尺寸获取断点信息并进行响应式布局。该组件通过双向绑定实时返回容器的尺寸和断点,使开发者能够基于容器大小进行差异化的组件创建和布局。容器断点基于组件自身的实际尺寸和断点阈值数组确定高度和宽度断点值,组件尺寸和断点信息仅作用于当前组件及其子组件,同一页面中的多个容器可拥有各自独立的断点状态。

六、多元化习题

习题 1(判断题)

题目:分布式软总线提供了内置的持久化任务队列和自动重试机制,当目标设备离线时,未完成的任务会自动排队并重试。

答案:错误

解读 :分布式软总线本身是"尽力而为"的,保证传输可靠性但不保证传输稳定性,不提供内置的持久化任务队列或自动重试。开发者需要通过监听设备上下线状态(如on('deviceStateChange'))来实现自定义的容错恢复逻辑。

习题 2(单选题)

题目:以下哪个模块是HarmonyOS中负责设备发现、认证和状态管理的"设备管家"?

A. distributedDataObject

B. distributedDeviceManager

C. continueManager

D. abilityConnectionManager

答案:B

解读 :@ohos.distributedDeviceManager模块提供分布式设备管理能力,负责注册和解除注册设备上下线变化监听、发现周边不可信设备、认证设备、查询可信设备列表等。如果把分布式软总线比作"通信管道",那DeviceManager就是管道上的"调度中心"。

习题 3(多选题)

题目:关于分布式数据对象的冲突处理,以下说法正确的有(多选):

A. 系统默认采用后写覆盖先写(LWW)策略

B. 系统提供了自定义冲突策略接口,开发者可以注册回调

C. 避免冲突的方法是在应用层加版本号或时间戳

D. 分布式数据对象的sessionId为空的设备无法与其他设备同步

答案:A、C、D

解读:分布式数据对象默认采用后写覆盖先写(LWW)策略,选项A正确。系统不提供自定义冲突策略接口,自定义冲突合并全部在业务层实现,选项B错误。避免冲突的方法是在应用层加版本号或时间戳,同步后比对,按业务规则合并,选项C正确。sessionId为空的设备无法与其他设备同步,分布式数据对象退化为本地数据对象,选项D正确。

习题 4(代码填空题)

题目:请补全以下代码,使分布式数据对象能够跨设备同步数据,并监听远端数据变化。

typescript 复制代码
import { distributedDataObject } from '@kit.ArkData';

// 创建分布式数据对象
this.dataObject = distributedDataObject.create(this.context, {
  title: '',
  isCompleted: false
});

// 监听远端数据变更
this.dataObject.______________('dataChange', distributedDataObject.DataObjectChangeType.change, () => {
  this.todoTitle = this.dataObject['title'] as string;
  this.isCompleted = this.dataObject['isCompleted'] as boolean;
});

// 加入同步会话
this.dataObject.______________('todo_sync_session_001');

答案 :on、setSessionId

解读 :on方法用于监听数据变化事件,dataChange事件在远端数据变更时触发。setSessionId方法用于将分布式数据对象加入指定的同步会话,设置相同的sessionId的设备之间会自动同步数据。

习题 5(代码改错题)

题目:以下应用接续代码存在错误,请指出问题并修正。

typescript 复制代码
export default class EntryAbility extends UIAbility {
  onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
    // 直接传递大量数据
    wantParam['todoList'] = JSON.stringify(this.getLargeTodoList());  // 超过1MB
    wantParam['imageData'] = this.getImageBase64();  // 大图片
    return AbilityConstant.OnContinueResult.AGREE;
  }
}

答案 :在onContinue回调中使用wantParam传输的数据需要控制在100KB以下,大量数据应使用分布式对象迁移数据。修正方案是将大数据量通过分布式数据对象同步,wantParam中只传递少量关键信息:

typescript 复制代码
export default class EntryAbility extends UIAbility {
  onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
    // wantParam只传递少量关键信息(<100KB)
    wantParam['pageRoute'] = 'TodoList';
    wantParam['scrollOffset'] = 320;

    // 大数据量通过分布式数据对象迁移
    const syncData = distributedDataObject.create(this.context, {
      todoList: JSON.stringify(this.getLargeTodoList()),
      lastSyncTime: Date.now()
    });
    syncData.setSessionId('continue_session_' + Date.now());

    return AbilityConstant.OnContinueResult.AGREE;
  }
}

解读 :onContinue回调中wantParam传输的数据需要控制在100KB以下,大数据量请使用分布式对象迁移数据。

习题 6(简答题)

题目:简述分布式数据对象的生命周期状态,以及各状态之间的转换条件。

答案 :分布式数据对象的生命周期包括三种状态。未初始化 :未实例化或已被销毁。本地数据对象 :已创建对应的数据表,但还无法进行数据同步。分布式数据对象:已创建对应的数据表,设备在线且组网内设置同样sessionId的对象数≥2,可以跨设备同步数据。状态转换条件:当创建分布式数据对象并设置sessionId,且组网内至少有2个设备设置了相同sessionId时,从本地数据对象变为分布式数据对象;若设备掉线或将sessionId置为空,则退化为本地数据对象;销毁后回到未初始化状态。

解读:理解分布式数据对象的生命周期状态有助于正确管理对象的创建、同步和销毁时机。在设备上下线时,对象会在本地和分布式状态之间自动切换。

习题 7(简答题)

题目:简述一次开发多端部署中三层工程架构的职责划分,以及各层之间的依赖关系。

答案:三层工程架构包括products(产品定制层)、features(基础特性层)和common(公共能力层)。products层针对不同设备形态进行功能和特性集成,各个子目录各自编译为一个Entry类型的HAP包作为应用主入口,向下依赖features层和common层,各product间不可相互依赖。features层抽象应用基础特性,需要单独部署的feature编译为Feature类型的HAP包,可以横向调用及依赖common层,同时可以被products层不同设备形态的HAP所依赖,但不能反向依赖products层。common层提供基础特性层依赖的公共能力,如UI组件、工具类,编译为HAR包或HSP包。

解读:三层架构的核心价值在于解耦与复用。products层面向设备差异,features层面向业务特性,common层面向通用能力。通过清晰的依赖关系(products → features → common),实现"一次开发,多端部署"的目标。

七、本节知识点总结

分布式软总线

HarmonyOS分布式能力的通信基座,提供设备发现、认证和统一传输接口。是"尽力而为"的实时通信,不提供内置持久化任务队列或自动重试,开发者需自行实现容错逻辑。

设备管理

distributedDeviceManager是分布式设备管理的"调度中心",提供设备发现、认证、可信设备列表查询和上下线监听能力。核心API包括createDeviceManager、getAvailableDeviceListSync、on('deviceStateChange')等。

分布式数据对象

对"变量"的"全局"访问,将跨设备数据同步封装为本地变量操作。通过相同的sessionId建立同步关系,默认采用后写覆盖先写(LWW)策略,应用层可通过版本号或时间戳实现自定义冲突合并。

键值型数据库

单版本数据库全局保留一份数据,适合联系人、天气等场景;多设备协同数据库按设备维度管理数据,适合图库缩略图等场景。支持手动同步(PULL_ONLY/PUSH_ONLY/PUSH_PULL)和自动同步两种方式。

应用接续

通过onContinue保存迁移数据、onCreate/onNewWant恢复迁移数据实现跨设备任务无缝衔接。wantParam传输数据需控制在100KB以下,大数据量使用分布式对象迁移。双端需登录同一华为账号,打开WLAN和蓝牙,开启接续功能。

一次开发多端部署

采用common(公共能力)、features(基础特性)、products(产品定制)三层工程架构。断点系统分为横向断点(窗口宽度:xs/sm/md/lg/xl)和纵向断点(高宽比:sm/md/lg),面向窗口而非设备类型。

下节预告

第10课将进入ArkUI应用架构设计与工程化最佳实践的学习,涵盖大型应用模块拆分策略、依赖治理、构建优化以及团队协作规范。

相关推荐
shangan_31 小时前
C语言学习
c语言·开发语言·学习
每天题库1 小时前
汽车维修工考试题库:真题错题复盘与高频考点清单
学习·安全·考试·题库·考证
李游Leo1 小时前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 输入帧内参与位姿的版本一致性门禁【鸿蒙心迹】
c++·3d·harmonyos
tsqtsqtsq03091 小时前
Account Kit 华为账号服务介绍
华为·harmonyos
EatFan1 小时前
Flutter 鸿蒙适配实践 2026:从环境搭建、混合渲染到 OpenTelemetry 性能基建
flutter·华为·harmonyos·openharmony·opentelemetry·鸿蒙适配·impeller
阳光九叶草LXGZXJ2 小时前
达梦数据库-学习-71-存过执行过程中重建存过影响验证
linux·运维·数据库·sql·学习
m0_738185822 小时前
Flutter 鸿蒙化实战:flutter_secure_storage 适配 OpenHarmony,敏感数据安全存储
安全·flutter·华为·harmonyos·鸿蒙
李游Leo2 小时前
HarmonyOS 7 HiAppEvent + AppGallery Connect:审核复现链路的脱敏日志切片与证据校验【鸿蒙心迹】
华为·harmonyos
李游Leo2 小时前
HarmonyOS 7 + Core Vision Kit:文搜图索引代际切换与模型升级回滚【鸿蒙心迹】
华为·harmonyos