0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

HarmonyOS開發(fā)實(shí)例:【分布式手寫板】

jf_46214456 ? 來(lái)源:jf_46214456 ? 作者:jf_46214456 ? 2024-04-17 21:45 ? 次閱讀

介紹

本篇Codelab使用設(shè)備管理及分布式鍵值數(shù)據(jù)庫(kù)能力,實(shí)現(xiàn)多設(shè)備之間手寫板應(yīng)用拉起及同步書寫內(nèi)容的功能。操作流程:

  1. 設(shè)備連接同一無(wú)線網(wǎng)絡(luò),安裝分布式手寫板應(yīng)用。進(jìn)入應(yīng)用,點(diǎn)擊允許使用多設(shè)備協(xié)同,點(diǎn)擊主頁(yè)上查詢?cè)O(shè)備按鈕,顯示附近設(shè)備。
  2. 選擇設(shè)備確認(rèn),若已建立連接,啟動(dòng)對(duì)方設(shè)備上的手寫板應(yīng)用,否則提示建立連接。輸入PIN碼建立連接后再次點(diǎn)擊查詢?cè)O(shè)備按鈕,選擇設(shè)備提交,啟動(dòng)對(duì)方設(shè)備應(yīng)用。
  3. 建立連接前繪制的內(nèi)容在啟動(dòng)對(duì)方設(shè)備后同步,此時(shí)設(shè)備上繪制的內(nèi)容會(huì)在另一端同步繪制。
  4. 點(diǎn)擊撤銷按鈕,兩側(cè)設(shè)備繪制內(nèi)容同步撤銷。

相關(guān)概念

  • [設(shè)備管理]:模塊提供分布式設(shè)備管理能力。
  • [分布式鍵值數(shù)據(jù)庫(kù)]:分布式鍵值數(shù)據(jù)庫(kù)為應(yīng)用程序提供不同設(shè)備間數(shù)據(jù)庫(kù)的分布式協(xié)同能力。

相關(guān)權(quán)限

本篇Codelab使用了設(shè)備管理及分布式鍵值數(shù)據(jù)庫(kù)能力,需要手動(dòng)替換full-SDK,并在配置文件module.json5文件requestPermissions屬性中添加如下權(quán)限:

  • [分布式設(shè)備認(rèn)證組網(wǎng)權(quán)限]:ohos.permission.ACCESS_SERVICE_DM。
  • [設(shè)備間的數(shù)據(jù)交換權(quán)限]:ohos.permission.DISTRIBUTED_DATASYNC。

約束與限制

  1. 本篇Codelab部分能力依賴于系統(tǒng)API,需下載full-SDK并替換DevEco Studio自動(dòng)下載的public-SDK。
  2. 本篇Codelab使用的部分API僅系統(tǒng)應(yīng)用可用,需要提升應(yīng)用等級(jí)。

環(huán)境搭建

軟件要求

  • [DevEco Studio]版本:DevEco Studio 4.0 Beta2。
  • OpenHarmony SDK版本:API version 10。
  • 鴻蒙指導(dǎo)參考:[qr23.cn/AKFP8k]

搜狗高速瀏覽器截圖20240326151547.png

硬件要求

  • 開發(fā)板類型:[潤(rùn)和RK3568開發(fā)板]。
  • OpenHarmony系統(tǒng):4.0 Release。

環(huán)境搭建

完成本篇Codelab我們首先要完成開發(fā)環(huán)境的搭建,本示例以RK3568開發(fā)板為例,參照以下步驟進(jìn)行:

  1. [獲取OpenHarmony系統(tǒng)版本]:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)。以4.0 Release版本為例:
  2. 搭建燒錄環(huán)境。
    1. [完成DevEco Device Tool的安裝]
    2. [完成RK3568開發(fā)板的燒錄]
  3. 搭建開發(fā)環(huán)境。
    1. 開始前請(qǐng)參考[工具準(zhǔn)備],完成DevEco Studio的安裝和開發(fā)環(huán)境配置。
    2. 開發(fā)環(huán)境配置完成后,請(qǐng)參考[使用工程向?qū)創(chuàng)建工程(模板選擇“Empty Ability”)。
    3. 工程創(chuàng)建完成后,選擇使用[真機(jī)進(jìn)行調(diào)測(cè)]。

代碼結(jié)構(gòu)解讀

本篇Codelab只對(duì)核心代碼進(jìn)行講解,對(duì)于完整代碼,我們會(huì)在gitee中提供。

├──entry/src/main/ets                 // 代碼區(qū)
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets       // 公共常量類
│  │  └──utils
│  │     ├──Logger.ets                // 日志打印類
│  │     └──RemoteDeviceUtil.ets      // 設(shè)備管理類
│  ├──entryability
│  │  └──EntryAbility.ets             // 程序入口類
│  ├──pages
│  │  └──Index.ets                    // 主界面
│  ├──view
│  │  └──CustomDialogComponent.ets    // 自定義彈窗組件類
│  └──viewmodel
│     ├──KvStoreModel.ets             // 分布式鍵值數(shù)據(jù)庫(kù)管理類
│     └──Position.ets                 // 繪制位置信息
└──entry/src/main/resources           // 資源文件目錄

界面設(shè)計(jì)

主界面由導(dǎo)航欄及繪制區(qū)域組成,導(dǎo)航欄包含撤回按鈕及查詢?cè)O(shè)備按鈕。繪制區(qū)域使用Canvas畫布組件展示繪制效果。Index.ets文件完成界面實(shí)現(xiàn),使用Column及Row容器組件進(jìn)行布局。

// Index.ets
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
struct Index {
  ...
  build() {
    Column() {
      Row() {
        // 撤回按鈕
        Image($r('app.media.ic_back'))
          .width($r('app.float.ic_back_width'))
          .height($r('app.float.ic_back_height'))
          ...
        Blank()
        // 查找設(shè)備按鈕
        Image($r('app.media.ic_hop'))
          .width($r('app.float.ic_hop_width'))
          .height($r('app.float.ic_hop_height'))
          ...
      }
      .width(CommonConstants.FULL_PERCENT)
      .height(CommonConstants.TITLE_HEIGHT)

      Row() {
        // 繪制區(qū)域
        Canvas(this.canvasContext)
          .width(CommonConstants.FULL_PERCENT)
          .height(CommonConstants.FULL_PERCENT)
          ...
      }
      ...
      .width(CommonConstants.FULL_PERCENT)
      .layoutWeight(CommonConstants.NUMBER_ONE)
    }
    .height(CommonConstants.FULL_PERCENT)
    .width(CommonConstants.FULL_PERCENT)
  }
  ...
}

分布式組網(wǎng)

準(zhǔn)備分布式環(huán)境

創(chuàng)建設(shè)備管理器。設(shè)備管理器創(chuàng)建完成后注冊(cè)設(shè)備上線離線監(jiān)聽,信任設(shè)備上線離線時(shí)觸發(fā)。執(zhí)行獲取本地設(shè)備信息,獲取信任設(shè)備列表,初始化展示設(shè)備列表等方法。其中deviceManager類需使用full-SDK。

// RemoteDeviceUtil.ets
import deviceManager from '@ohos.distributedHardware.deviceManager';

class RemoteDeviceUtil {
  ...
  async createDeviceManager() {
    ...
    await new Promise((resolve: (value: Object | PromiseLike< Object >) = > void, reject: ((reason?: RejectError) = > void)) = > {
      try {
        // 創(chuàng)建設(shè)備管理器
        deviceManager.createDeviceManager(CommonConstants.BUNDLE_NAME,
          (error, value: deviceManager.DeviceManager) = > {
            ...
            this.myDeviceManager = value;
            // 注冊(cè)信任設(shè)備上線離線監(jiān)聽
            this.registerDeviceStateListener();
            // 獲取本地設(shè)備信息
            this.getLocalDeviceInfo();
            // 獲取信任設(shè)備列表
            this.getTrustedDeviceList();
            // 初始化展示設(shè)備列表
            this.initDeviceList();
            resolve(value);
        });
      } catch (error) {
        Logger.error('RemoteDeviceModel',
          `createDeviceManager failed, error=${JSON.stringify(error)}`);
      }
    });
  }
  ...
}

注冊(cè)設(shè)備狀態(tài)監(jiān)聽。已驗(yàn)證設(shè)備上線或有新設(shè)備驗(yàn)證通過(guò)時(shí)狀態(tài)類型為ONLINE,將設(shè)備添加至信任設(shè)備列表。設(shè)備離線時(shí)狀態(tài)類型為OFFLINE,將設(shè)備從信任列表中移除。

// RemoteDeviceUtil.ets
class RemoteDeviceUtil {
  ...
  // 注冊(cè)設(shè)備狀態(tài)改變監(jiān)聽
  registerDeviceStateListener(): void {
    ...
    try {
      // 注冊(cè)監(jiān)聽
      this.myDeviceManager.on('deviceStateChange', (data) = > {
        ...
        switch (data.action) {
          // 設(shè)備上線
          case deviceManager.DeviceStateChangeAction.ONLINE: {
            this.deviceStateChangeActionOnline(data.device);
            break;
          }
          // 設(shè)備離線
          case deviceManager.DeviceStateChangeAction.OFFLINE: {
            this.deviceStateChangeActionOffline(data.device);
            break;
          }
          ...
        }
      });
    } catch (error) {
      Logger.error('RemoteDeviceModel',
        `registerDeviceStateListener on('deviceStateChange') failed, error=${JSON.stringify(error)}`);
    }
  }

  // 設(shè)備上線,加入信任列表及展示列表
  deviceStateChangeActionOnline(device: deviceManager.DeviceInfo): void {
    this.trustedDeviceList[this.trustedDeviceList.length] = device;
    this.addToDeviceList(device);
  }

  // 設(shè)備下線,將設(shè)備移出信任列表和展示列表
  deviceStateChangeActionOffline(device: deviceManager.DeviceInfo): void {
    let list: deviceManager.DeviceInfo[] = [];
    for (let i: number = 0; i < this.trustedDeviceList.length; i++) {
      if (this.trustedDeviceList[i].networkId !== device.networkId) {
        list.push(this.trustedDeviceList[i]);
        continue;
      }
    }
    this.deleteFromDeviceList(device);
    this.trustedDeviceList = list;
  }
  ...
}

建立分布式連接

點(diǎn)擊主界面的查詢?cè)O(shè)備按鈕,執(zhí)行發(fā)現(xiàn)設(shè)備方法,注冊(cè)設(shè)備發(fā)現(xiàn)監(jiān)聽任務(wù),同時(shí)拉起彈窗展示設(shè)備列表。當(dāng)彈窗關(guān)閉時(shí),執(zhí)行停止發(fā)現(xiàn)設(shè)備方法,注銷監(jiān)聽任務(wù)。

// RemoteDeviceUtil.ets
class RemoteDeviceUtil {
  ...
  // 處理新發(fā)現(xiàn)的設(shè)備
  deviceFound(data: DeviceInfoInterface): void {
    for (let i: number = 0; i < this.discoverList.length; i++) {
      if (this.discoverList[i].deviceId === data.device.deviceId) {
        Logger.info('RemoteDeviceModel', `deviceFound device exist=${JSON.stringify(data)}`);
        return;
      }
    }
    this.discoverList[this.discoverList.length] = data.device;
    this.addToDeviceList(data.device);
  }

  startDeviceDiscovery(): void {
    ...
    try {
      // 注冊(cè)發(fā)現(xiàn)設(shè)備監(jiān)聽
      this.myDeviceManager.on('deviceFound', (data) = > {
        ...
        // 處理發(fā)現(xiàn)的設(shè)備
        this.deviceFound(data);
      });
      ...
      let info: deviceManager.SubscribeInfo = {
        subscribeId: this.subscribeId,
        mode: CommonConstants.SUBSCRIBE_MODE,
        medium: CommonConstants.SUBSCRIBE_MEDIUM,
        freq: CommonConstants.SUBSCRIBE_FREQ,
        isSameAccount: false,
        isWakeRemote: true,
        capability: CommonConstants.SUBSCRIBE_CAPABILITY
      };
      // 發(fā)現(xiàn)周邊設(shè)備
      this.myDeviceManager.startDeviceDiscovery(info);
    } catch (error) {
      Logger.error('RemoteDeviceModel',
        `startDeviceDiscovery failed error=${JSON.stringify(error)}`);
    }
  }

  // 停止發(fā)現(xiàn)設(shè)備
  stopDeviceDiscovery(): void {
    ...
    try {
      // 停止發(fā)現(xiàn)設(shè)備
      this.myDeviceManager.stopDeviceDiscovery(this.subscribeId);
      // 注銷監(jiān)聽任務(wù)
      this.myDeviceManager.off('deviceFound');
      this.myDeviceManager.off('discoverFail');
    } catch (error) {
      Logger.error('RemoteDeviceModel',
        `stopDeviceDiscovery failed error=${JSON.stringify(error)}`);
    }
  }
  ...
}

選擇彈窗內(nèi)的設(shè)備項(xiàng)提交后,執(zhí)行設(shè)備驗(yàn)證。

  1. 若設(shè)備在信任設(shè)備列表,執(zhí)行startAbility()方法啟動(dòng)連接設(shè)備上的應(yīng)用,將當(dāng)前的繪制信息作為參數(shù)發(fā)送至連接設(shè)備。
  2. 若設(shè)備不是信任設(shè)備,執(zhí)行authenticateDevice()方法啟動(dòng)驗(yàn)證。此時(shí)連接設(shè)備提示是否接受,接收連接后連接設(shè)備展示PIN碼,本地設(shè)備輸入PIN碼確認(rèn)后連接成功。再次點(diǎn)擊查詢?cè)O(shè)備按鈕,選擇已連接設(shè)備,點(diǎn)擊確認(rèn)啟動(dòng)連接設(shè)備上的應(yīng)用。
// RemoteDeviceUtil.ets
class RemoteDeviceUtil {
  ...
  // 設(shè)備驗(yàn)證
  authenticateDevice(
    context: common.UIAbilityContext,
    device: deviceManager.DeviceInfo,
    positionList: Position[]
  ): void {
    // 設(shè)備為信任設(shè)備,啟動(dòng)連接設(shè)備上的應(yīng)用
    let tmpList = this.trustedDeviceList.filter((item: deviceManager.DeviceInfo) = > device.deviceId === item.deviceId);
    if (tmpList.length > 0) {
      this.startAbility(context, device, positionList);
      return;
    }
    ...
    try {
      // 執(zhí)行設(shè)備認(rèn)證,啟動(dòng)驗(yàn)證相關(guān)彈窗,接受信任,顯示PIN碼,輸入PIN碼等
      this.myDeviceManager.authenticateDevice(device, authParam, (err) = > {
        ...
      })
    } catch (error) {
      Logger.error('RemoteDeviceModel',
        `authenticateDevice failed error=${JSON.stringify(error)}`);
    }
  }

  // 啟動(dòng)連接設(shè)備上的應(yīng)用
  startAbility(context: common.UIAbilityContext, device: deviceManager.DeviceInfo, positionList: Position[]): void {
    ...
    // 啟動(dòng)連接設(shè)備上的應(yīng)用
    context.startAbility(wantValue).then(() = > {
      Logger.info('RemoteDeviceModel', `startAbility finished wantValue=${JSON.stringify(wantValue)}`);
    }).catch((error: Error) = > {
      Logger.error('RemoteDeviceModel', `startAbility failed, error=${JSON.stringify(error)}`);
    })
  }
  ...
}

資源釋放

程序關(guān)閉時(shí),注銷設(shè)備狀態(tài)監(jiān)聽任務(wù),并釋放DeviceManager實(shí)例。

// RemoteDeviceUtil.ets
class RemoteDeviceUtil {
  ...
  // 注銷監(jiān)聽任務(wù)
  unregisterDeviceListCallback(): void {
    ...
    try {
      // 注銷設(shè)備狀態(tài)監(jiān)聽
      this.myDeviceManager.off('deviceStateChange');
      // 釋放DeviceManager實(shí)例
      this.myDeviceManager.release();
    } catch (err) {
      Logger.error('RemoteDeviceModel',
        `unregisterDeviceListCallback stopDeviceDiscovery failed, error=${JSON.stringify(err)}`);
    }
  }
  ...
}

繪制功能

Canvas組件區(qū)域監(jiān)聽觸摸事件,按照按下、移動(dòng)、抬起等觸摸事件,記錄繪制的起點(diǎn)、中間點(diǎn)以及終點(diǎn)。觸摸事件觸發(fā)時(shí),使用CanvasRenderingContext2D對(duì)象的繪制方法根據(jù)位置信息進(jìn)行繪制。繪制結(jié)束后,將當(dāng)前位置信息列表存入分布式鍵值數(shù)據(jù)庫(kù)。

// Index.ets
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
struct Index {
  ...  
  build() {
    Column() {
      ...
      Row() {
        Canvas(this.canvasContext)
          ...
      }
      .onTouch((event: TouchEvent) = > {
        this.onTouchEvent(event);
      })
      ...
    }
    ...
  }

  // 繪制事件
  onTouchEvent(event: TouchEvent): void {
    let positionX: number = event.touches[0].x;
    let positionY: number = event.touches[0].y;
    switch (event.type) {
      // 手指按下
      case TouchType.Down: {
        this.canvasContext.beginPath();
        this.canvasContext.lineWidth = CommonConstants.CANVAS_LINE_WIDTH;
        this.canvasContext.lineJoin = CommonConstants.CANVAS_LINE_JOIN;
        this.canvasContext.moveTo(positionX, positionY);
        this.pushData(true, false, positionX, positionY);
        break;
      }
      // 手指移動(dòng)
      case TouchType.Move: {
        this.canvasContext.lineTo(positionX, positionY);
        this.pushData(false, false, positionX, positionY);
        break;
      }
      // 手指抬起
      case TouchType.Up: {
        this.canvasContext.lineTo(positionX, positionY);
        this.canvasContext.stroke();
        this.pushData(false, true, positionX, positionY);
        break;
      }
      default: {
        break;
      }
    }
  }

  pushData(isFirstPosition: boolean, isEndPosition: boolean, positionX: number, positionY: number): void {
    let position = new Position(isFirstPosition, isEndPosition, positionX, positionY);
    // 存入位置信息列表
    this.positionList.push(position);
    if (position.isEndPosition) {
      // 當(dāng)前位置為終點(diǎn)時(shí),將位置信息列表存入分布式鍵值數(shù)據(jù)庫(kù)
      this.kvStoreModel.put(CommonConstants.CHANGE_POSITION, JSON.stringify(this.positionList));
    }
  }
  ...
}

點(diǎn)擊撤銷按鈕時(shí),從位置列表中后序遍歷移除位置信息,直到找到軌跡的初始位置,完成移除上一次繪制的軌跡。移除完成后將位置信息列表存入分布式鍵值數(shù)據(jù)庫(kù)中。執(zhí)行redraw()方法,清空畫板上的內(nèi)容,遍歷位置信息列表,重新繪制。

// Index.ets
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
struct Index {
  ...
  @LocalStorageProp('positionList') positionList: Position[] = [];
  ...
  build() {
    Column() {
      Row() {
        // 撤銷按鈕
        Image($r('app.media.ic_back'))
          .width($r('app.float.ic_back_width'))
          .height($r('app.float.ic_back_height'))
          .margin({ left: CommonConstants.ICON_MARGIN_LEFT })
          .onClick(() = > {
            this.goBack();
          })
        ...
      }
      .width(CommonConstants.FULL_PERCENT)
      .height(CommonConstants.TITLE_HEIGHT)
      ...
  }

  ...
  redraw(): void {
    // 刪除畫布內(nèi)的繪制內(nèi)容
    this.canvasContext.clearRect(0, 0, this.canvasContext.width, this.canvasContext.height);
    // 使用當(dāng)前記錄的位置信息,重新繪制
    this.positionList.forEach((position) = > {
      ...
      if (position.isFirstPosition) {
        this.canvasContext.beginPath();
        this.canvasContext.lineWidth = CommonConstants.CANVAS_LINE_WIDTH;
        this.canvasContext.lineJoin = CommonConstants.CANVAS_LINE_JOIN;
        this.canvasContext.moveTo(position.positionX, position.positionY);
      } else {
        this.canvasContext.lineTo(position.positionX, position.positionY);
        if (position.isEndPosition) {
          this.canvasContext.stroke();
        }
      }
    });
  }


  // 撤回上一筆繪制
  goBack(): void {
    if (this.positionList.length === 0) {
      return;
    }
    // 移除位置信息直到位置起始位置
    for (let i: number = this.positionList.length - 1; i >= 0; i--) {
      let position: Position | undefined = this.positionList.pop();
      if (position !== undefined && position.isFirstPosition) {
        break;
      }
    }
    this.redraw();
    this.kvStoreModel.put(CommonConstants.CHANGE_POSITION, JSON.stringify(this.positionList));
  }
  ...
}

分布式鍵值數(shù)據(jù)庫(kù)

使用分布式鍵值數(shù)據(jù)庫(kù)需申請(qǐng)數(shù)據(jù)交換權(quán)限:ohos.permission.DISTRIBUTED_DATASYNC。

應(yīng)用啟動(dòng)時(shí)創(chuàng)建分布式鍵值數(shù)據(jù)庫(kù),設(shè)置數(shù)據(jù)庫(kù)數(shù)據(jù)改變監(jiān)聽。數(shù)據(jù)改變時(shí)執(zhí)行回調(diào),獲取插入或更新數(shù)據(jù)列表,遍歷列表,匹配位置信息列表的設(shè)置key,更新位置列表后重新繪制。

// Index.ets
...
import KvStoreModel from '../viewmodel/KvStoreModel';
...
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
struct Index {
  ...
  private kvStoreModel: KvStoreModel = new KvStoreModel();
  ...
  aboutToAppear() {
    ...
    this.createKVStore();
  }

  ...
  createKVStore(): void {
    // 創(chuàng)建分布式鍵值數(shù)據(jù)庫(kù)
    this.kvStoreModel.createKvStore(this.context, (data: distributedKVStore.ChangeNotification) = > {
      // 使用分布式鍵值數(shù)據(jù)庫(kù)內(nèi)的內(nèi)容重置位置信息列表
      this.positionList = [];
      let entries: distributedKVStore.Entry[] = data.insertEntries.length > 0 ? data.insertEntries : data.updateEntries;
      entries.forEach((entry: distributedKVStore.Entry) = > {
        if (CommonConstants.CHANGE_POSITION === entry.key) {
          this.positionList = JSON.parse((entry.value.value) as string);
          // 位置信息列表更新后,重新繪制
          this.redraw();
        }
      });
    });
  }
  ...
}

創(chuàng)建分布式鍵值數(shù)據(jù)庫(kù)。設(shè)置數(shù)據(jù)庫(kù)類型為KVStoreType.SINGLE_VERSION單版本數(shù)據(jù)庫(kù),其他配置參考[創(chuàng)建數(shù)據(jù)庫(kù)配置信息]。創(chuàng)建數(shù)據(jù)庫(kù)成功后,調(diào)用enableSync()方法開啟同步,調(diào)用setDataChangeListener()方法訂閱數(shù)據(jù)變更通知。

// KvStoreModel.ets
export default class KvStoreModel {
  ...
  kvStore?: distributedKVStore.SingleKVStore;
  ...
  createKvStore(
    context: common.UIAbilityContext,
    callback: (data: distributedKVStore.ChangeNotification) = > void
  ): void {
    ...
    try {
      // 創(chuàng)建一個(gè)KVManager對(duì)象實(shí)例,用于管理數(shù)據(jù)庫(kù)對(duì)象
      this.kvManager = distributedKVStore.createKVManager(config);
    } catch (error) {
      Logger.error('KvStoreModel',
        `createKvStore createKVManager failed, err=${JSON.stringify(error)}`);
      return;
    }

    // 創(chuàng)建數(shù)據(jù)庫(kù)的配置信息
    let options: distributedKVStore.Options = {
      ...
      kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION
      ...
    };

    // 獲取分布式鍵值數(shù)據(jù)庫(kù)
    this.kvManager.getKVStore(CommonConstants.KVSTORE_ID, options).then((store: distributedKVStore.SingleKVStore) = > {
      ...
      this.kvStore = store;
      // 開啟同步
      this.kvStore.enableSync(true).then(() = > {
        Logger.info('KvStoreModel', 'createKvStore enableSync success');
      }).catch((error: Error) = > {
        Logger.error('KvStoreModel',
          `createKvStore enableSync fail, error=${JSON.stringify(error)}`);
      });
      this.setDataChangeListener(callback);
    }).catch((error: Error) = > {
      Logger.error('getKVStore',
        `createKvStore getKVStore failed, error=${JSON.stringify(error)}`);
    })
  }
  ...
}

訂閱數(shù)據(jù)變更通知。創(chuàng)建分布式鍵值數(shù)據(jù)庫(kù),設(shè)置數(shù)據(jù)變更訂閱,訂閱類型為全部,當(dāng)更新數(shù)據(jù)集或插入數(shù)據(jù)集大于0時(shí),執(zhí)行傳入的callback()方法。

// KvStoreModel.ets
export default class KvStoreModel {
  ...
  kvStore?: distributedKVStore.SingleKVStore;
  ...
  setDataChangeListener(callback: (data: distributedKVStore.ChangeNotification) = > void): void {
    ...
    try {
      // 訂閱數(shù)據(jù)變更通知
      this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL,
        (data: distributedKVStore.ChangeNotification) = > {
          if ((data.updateEntries.length > 0) || (data.insertEntries.length > 0)) {
            callback(data);
          }
        });
    } catch (error) {
      Logger.error('KvStoreModel',
        `setDataChangeListener on('dataChange') failed, err=${JSON.stringify(error)}`);
    }
  }
  ...
}

應(yīng)用退出時(shí),分布式鍵值數(shù)據(jù)庫(kù)取消數(shù)據(jù)改變監(jiān)聽。

// Index.ets
...
import KvStoreModel from '../viewmodel/KvStoreModel';
...
let storage = LocalStorage.getShared();
@Entry(storage)
@Component
struct Index {
  ...
  private kvStoreModel: KvStoreModel = new KvStoreModel();
  ...
  aboutToDisappear() {
    this.kvStoreModel.removeDataChangeListener();
  }
  ...
}

// KvStoreModel.ets
export default class KvStoreModel {
  ...
  kvStore?: distributedKVStore.SingleKVStore;
  ...
  removeDataChangeListener(): void {
    ...
    try {
      // 取消數(shù)據(jù)改變監(jiān)聽
      this.kvStore.off('dataChange');
    } catch (error) {
      Logger.error('KvStoreModel',
        `removeDataChangeListener off('dataChange') failed, err=${JSON.stringify(error)}`);
    }
  }
  ...
}

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 分布式
    +關(guān)注

    關(guān)注

    1

    文章

    899

    瀏覽量

    74509
  • HarmonyOS
    +關(guān)注

    關(guān)注

    79

    文章

    1975

    瀏覽量

    30201
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3722

    瀏覽量

    16320
  • 鴻蒙OS
    +關(guān)注

    關(guān)注

    0

    文章

    188

    瀏覽量

    4396
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    HarmonyOS開發(fā)實(shí)例:【分布式數(shù)據(jù)管理】

    eTS中分布式數(shù)據(jù)管理的使用,包括KVManager對(duì)象實(shí)例的創(chuàng)建和KVStore數(shù)據(jù)流轉(zhuǎn)的使用。
    的頭像 發(fā)表于 04-11 09:57 ?940次閱讀
    <b class='flag-5'>HarmonyOS</b><b class='flag-5'>開發(fā)</b><b class='flag-5'>實(shí)例</b>:【<b class='flag-5'>分布式</b>數(shù)據(jù)管理】

    手寫板

    手寫板不錯(cuò)的資料,值得學(xué)習(xí)
    發(fā)表于 07-15 21:48

    HarmonyOS應(yīng)用開發(fā)-分布式任務(wù)調(diào)度

    1. 介紹本篇CodeLab將實(shí)現(xiàn)的內(nèi)容HarmonyOS是面向全場(chǎng)景多終端的分布式操作系統(tǒng),使得應(yīng)用程序的開發(fā)打破了智能終端互通的性能和數(shù)據(jù)壁壘,業(yè)務(wù)邏輯原子化開發(fā),適配多端。通過(guò)一
    發(fā)表于 09-18 09:21

    HarmonyOS應(yīng)用開發(fā)-分布式設(shè)計(jì)

    設(shè)計(jì)理念HarmonyOS 是面向未來(lái)全場(chǎng)景智慧生活方式的分布式操作系統(tǒng)。對(duì)消費(fèi)者而言,HarmonyOS 將生活場(chǎng)景中的各類終端進(jìn)行能力整合,形成“One Super Device”,以實(shí)現(xiàn)
    發(fā)表于 09-22 17:11

    HarmonyOS實(shí)戰(zhàn)—基于分布式能力,實(shí)現(xiàn)多設(shè)備同步書寫互動(dòng)

    ,第三臺(tái)書寫筆跡是紅色(每臺(tái)設(shè)備的畫筆初始化時(shí)都會(huì)隨機(jī)一種顏色),每臺(tái)設(shè)備筆跡都會(huì)同步到連接的設(shè)備上顯示。圖3 分布式手寫板演示圖2. 搭建HarmonyOS環(huán)境我們首先需要完成Harmony
    發(fā)表于 09-03 17:14

    HarmonyOS分布式應(yīng)用框架深入解讀

    設(shè)備、分布式的能力及應(yīng)用,二者具有無(wú)限能力。從開發(fā)者角度看,HarmonyOS上基本的組件分為3+1,其中3代表三個(gè)Ability,分別是:PageAbility:負(fù)責(zé)用戶界面的顯示
    發(fā)表于 11-22 15:15

    如何高效完成HarmonyOS分布式應(yīng)用測(cè)試?

    作者:liuxun,HarmonyOS測(cè)試架構(gòu)師HarmonyOS是新一代的智能終端操作系統(tǒng),給開發(fā)者提供了設(shè)備發(fā)現(xiàn)、設(shè)備連接、跨設(shè)備調(diào)用等豐富的分布式API。隨著越來(lái)越多的
    發(fā)表于 12-13 18:07

    基于OpenHarmony3.1開發(fā)的一個(gè)分布式手寫板應(yīng)用

    1.介紹基于TS擴(kuò)展的聲明開發(fā)范式開發(fā)一個(gè)分布式手寫板應(yīng)用。涉及的OS特性有分布式拉起和
    發(fā)表于 04-07 11:42

    HarmonyOS應(yīng)用開發(fā)-EducationSystem分布式親子早教系統(tǒng)體驗(yàn)

    HarmonyOS應(yīng)用程序開發(fā),多屏協(xié)作交互和分布式跨設(shè)備傳輸?shù)慕?jīng)驗(yàn)。 ? 從項(xiàng)目創(chuàng)建、代碼編寫到編譯、構(gòu)造、部署和操作。二、效果圖:完整代碼地址:https://gitee.com/jltfcloudcn/jump_to/tr
    發(fā)表于 07-25 10:23

    HarmonyOS應(yīng)用開發(fā)-分布式語(yǔ)音攝像頭體驗(yàn)

    一、組件說(shuō)明使用HarmonyOS分布式文件系統(tǒng)和AI語(yǔ)音識(shí)別功能開發(fā)了一個(gè)分布式語(yǔ)音攝像頭。使用此相機(jī)應(yīng)用程序,同一分布式網(wǎng)絡(luò)下的不同設(shè)備
    發(fā)表于 08-24 15:06

    手寫板購(gòu)買指南

    手寫板購(gòu)買指南 手寫板簡(jiǎn)介 如何
    發(fā)表于 07-28 08:21 ?1564次閱讀

    如何選購(gòu)手寫板

    如何選購(gòu)手寫板 家用或繪畫愛好者使用的手寫板價(jià)格從不足700元至1750元不等,而專業(yè)手寫板的價(jià)格則在1400元左右至5250元之間乃至更高。帶有筆感應(yīng)數(shù)位屏的產(chǎn)品價(jià)格區(qū)
    發(fā)表于 07-28 08:22 ?1542次閱讀

    手寫板感應(yīng)方式

    手寫板感應(yīng)方式            &
    發(fā)表于 12-28 13:42 ?3446次閱讀

    HarmonyOS測(cè)試技術(shù)與實(shí)戰(zhàn)-HarmonyOS分布式應(yīng)用特征與挑戰(zhàn)

     HDC 2021華為開發(fā)者大會(huì)HarmonyOS測(cè)試技術(shù)與實(shí)戰(zhàn)-HarmonyOS分布式應(yīng)用特征與挑戰(zhàn)
    的頭像 發(fā)表于 10-23 14:41 ?1688次閱讀
    <b class='flag-5'>HarmonyOS</b>測(cè)試技術(shù)與實(shí)戰(zhàn)-<b class='flag-5'>HarmonyOS</b><b class='flag-5'>分布式</b>應(yīng)用特征與挑戰(zhàn)

    HarmonyOS分布式應(yīng)用上架問(wèn)題分析

    HarmonyOS是新一代的智能終端操作系統(tǒng),給開發(fā)者提供了設(shè)備發(fā)現(xiàn)、設(shè)備連接、跨設(shè)備調(diào)用等豐富的分布式API。隨著越來(lái)越多的開發(fā)者投入到Harmo
    的頭像 發(fā)表于 12-24 17:56 ?1913次閱讀
    <b class='flag-5'>HarmonyOS</b><b class='flag-5'>分布式</b>應(yīng)用上架問(wèn)題分析