分布式關(guān)系型數(shù)據(jù)庫(kù)
介紹
本示例使用[@ohos.data.relationalStore]接口和[@ohos.distributedDeviceManager] 接口展示了在eTS中分布式關(guān)系型數(shù)據(jù)庫(kù)的使用,在增、刪、改、查的基本操作外,還包括分布式數(shù)據(jù)庫(kù)的數(shù)據(jù)同步同能。
效果預(yù)覽

使用說(shuō)明:
- 啟動(dòng)應(yīng)用后點(diǎn)擊“ + ”按鈕可以添加聯(lián)系人;
- 點(diǎn)擊聯(lián)系人可以進(jìn)入編輯界面編輯聯(lián)系人信息;
- 長(zhǎng)按聯(lián)系人進(jìn)入多選狀態(tài),底部有“ 全選 ”、“ 取消 ”、“ 刪除 ”、“ 退出 ”按鈕,點(diǎn)擊退出可以退出多選狀態(tài);
- 點(diǎn)擊右上角更多按鈕,點(diǎn)擊“ 連接設(shè)備 ”,選擇要同步數(shù)據(jù)的設(shè)備,連接成功后可以開(kāi)始將本端數(shù)據(jù)同步到對(duì)端;
- 點(diǎn)擊右上角更多按鈕,點(diǎn)擊“ 設(shè)置 ”可以進(jìn)入設(shè)置界面設(shè)置數(shù)據(jù)同步方式,包括自動(dòng)同步和手動(dòng)同步。

具體實(shí)現(xiàn)
- 數(shù)據(jù)庫(kù)的增、刪、改、查操作都在RdbModel中,源碼參考[RdbModel.ets]:
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import data_rdb from '@ohos.data.relationalStore'
import common from '@ohos.app.ability.common'
import Contact from '../model/Contact'
import Logger from '../model/Logger'
import { STORE_CONFIG } from '../model/RdbConst'
import { ValuesBucket } from '@ohos.data.ValuesBucket';
const TAG = 'RdbModel'
export default class RdbModel {
private rdbStore: data_rdb.RdbStore | undefined = undefined
private tableName: string = ''
private sqlCreateTable: string = ''
private columns: Array< string > = []
private distributedTable: string = ''
private dataChangeCallback : Function| null = null
private isCreateDbDone: boolean = false
private context: common.UIAbilityContext
constructor(tableName: string, sqlCreateTable: string, columns: Array< string >, context: common.UIAbilityContext) {
this.tableName = tableName
this.sqlCreateTable = sqlCreateTable
this.columns = columns
this.context = context
this.getRdbStore()
}
// 初始化數(shù)據(jù)庫(kù)
async getRdbStore() {
Logger.info(TAG, 'getRdbStore begin')
if (this.isCreateDbDone) {
Logger.info(TAG, 'getRdbStore isCreateDbDone')
return
}
try {
// 獲取數(shù)據(jù)庫(kù)存儲(chǔ)對(duì)象
this.rdbStore = await data_rdb.getRdbStore(this.context, STORE_CONFIG);
} catch (err) {
console.info(`getRdbStore err ${JSON.stringify(err)}`);
}
Logger.info(TAG, 'getRdbStore end')
try {
// 執(zhí)行sql語(yǔ)句,聯(lián)系人個(gè)各個(gè)屬性設(shè)定
if(this.rdbStore != undefined) {
await this.rdbStore.executeSql(this.sqlCreateTable)
console.info(`create tabe start ` + this.sqlCreateTable);
// 設(shè)置分布式表,表明為contact
await this.rdbStore.setDistributedTables([this.tableName])
}
} catch (e) {
Logger.error(TAG, 'getRdbStore:' + JSON.stringify(e))
}
// 分布式數(shù)據(jù)庫(kù)創(chuàng)建為完成
this.isCreateDbDone = true
Logger.info(TAG, 'create table done')
}
async insertData(contact: Contact) {
let value1 = contact.name;
let value2 = contact.gender;
let value3 = contact.phone;
let value4 = contact.remark;
let value5 = contact.age;
const valueBucket: ValuesBucket = {
'name': value1,
'gender': value2,
'phone': value3,
'remark': value4,
'age': value5,
}
if(this.rdbStore != undefined) {
let ret = await this.rdbStore.insert(this.tableName, valueBucket, data_rdb.ConflictResolution.ON_CONFLICT_REPLACE)
Logger.info(TAG, `insert done:${ret}`)
}
}
async updateData(contact: Contact) {
let value1 = contact.name;
let value2 = contact.gender;
let value3 = contact.phone;
let value4 = contact.remark;
let value5 = contact.age;
const valueBucket: ValuesBucket = {
'name': value1,
'gender': value2,
'phone': value3,
'remark': value4,
'age': value5,
}
let predicates = new data_rdb.RdbPredicates(this.tableName)
Logger.info(TAG, `updateData id=${contact.id}`)
predicates.equalTo('id', contact.id)
if (this.rdbStore != undefined) {
let ret = await this.rdbStore.update(valueBucket, predicates)
Logger.info(TAG, `updated row count: ${ret}`)
}
}
async deleteContacts(contacts: Array< Contact >) {
let predicates = new data_rdb.RdbPredicates(this.tableName)
contacts.forEach((contact) = > {
predicates.or()
.equalTo('id', contact.id)
})
if (this.rdbStore != undefined) {
let rows = await this.rdbStore.delete(predicates)
Logger.info(TAG, `delete rows: ${rows}`)
}
}
async query(predicates: data_rdb.RdbPredicates): Promise< Array< Contact >> {
Logger.info(TAG, 'query start')
Logger.info(TAG, 'predicates is ' + JSON.stringify(predicates))
Logger.info(TAG, 'columns ' + JSON.stringify(this.columns))
if (this.rdbStore != undefined) {
// 默認(rèn)查詢(xún)所有列
let resultSet: data_rdb.ResultSet = await this.rdbStore.query(predicates, this.columns);
Logger.info(TAG, 'result is ' + JSON.stringify(resultSet.rowCount))
// 處理查詢(xún)到的結(jié)果數(shù)組
return this.getListFromResultSet(resultSet)
}
return []
}
async syncData(predicates: data_rdb.RdbPredicates) {
Logger.info(TAG, 'syncData')
if (this.rdbStore != undefined) {
let result = await this.rdbStore.sync(data_rdb.SyncMode.SYNC_MODE_PUSH, predicates)
for (let i = 0; i < result.length; i++) {
Logger.info(TAG, `device=${result[i][0]}, status = ${result[i][1]}`)
}
}
}
async onDataChange(device: string, callback: Function) {
Logger.info(TAG, `onDataChange enter,device=` + device + ` ,tableName = ` + this.tableName)
try {
if (this.rdbStore != undefined) {
this.distributedTable = await this.rdbStore.obtainDistributedTableName(device, this.tableName)
Logger.info(TAG, `obtainDistributedTableName,distributedTable=` + this.distributedTable)
}
}
catch (err) {
Logger.error(TAG, `ObtainDistributedTableName failed, code is ${err.code},message is ${err.message}`)
}
this.dataChangeCallback = callback
await this.pullData()
if (this.rdbStore != undefined) {
this.rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, async (devices) = > {
Logger.info(TAG, `on dataChange, callback`)
await this.pullData()
})
}
}
async pullData() {
Logger.info(TAG, `start pullData`)
if (this.rdbStore != undefined) {
await this.rdbStore.executeSql('delete from ' + this.tableName)
let predicates = new data_rdb.RdbPredicates(this.distributedTable)
let resultSet = await this.rdbStore.query(predicates, this.columns)
let result = this.getListFromResultSet(resultSet)
Logger.info(TAG, `on dataChange,result.length=${result.length}`)
for (let i = 0; i < result.length; i++) {
Logger.info(TAG, `on dataChange,insert${result[i].name}`)
let predicate = new data_rdb.RdbPredicates(this.tableName)
predicate.equalTo('name', result[i].name)
let exit = await this.rdbStore.query(predicate, this.columns)
exit.goToFirstRow()
if (exit.rowCount === 0) {
await this.insertData(result[i])
} else {
result[i].id = exit.getDouble(resultSet.getColumnIndex('id'))
await this.updateData(result[i])
}
}
if (this.dataChangeCallback != null) {
this.dataChangeCallback(result)
}
}
}
offDataChange() {
if(this.rdbStore != undefined) {
this.rdbStore.off('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (devices) = > {
for (let i = 0; i < devices.length; i++) {
Logger.info(TAG, `device=${devices[i]} off data changed`)
}
})
}
}
// 處理數(shù)據(jù)格式
getListFromResultSet(resultSet: data_rdb.ResultSet): Array< Contact > {
// 聲明結(jié)果變量
let contacts: Array< Contact > = []
// 進(jìn)入結(jié)果集的第一行
resultSet.goToFirstRow()
// 如果沒(méi)有結(jié)束就繼續(xù)遍歷
while (!resultSet.isEnded) {
// 讀取各個(gè)屬性,初始化臨時(shí)變量contact
let contact: Contact = new Contact(resultSet.getDouble(resultSet.getColumnIndex('id'))
, resultSet.getString(resultSet.getColumnIndex('name'))
, resultSet.getDouble(resultSet.getColumnIndex('gender'))
, resultSet.getString(resultSet.getColumnIndex('phone'))
, resultSet.getLong(resultSet.getColumnIndex('age'))
, resultSet.getString(resultSet.getColumnIndex('remark')))
if (!contacts.includes(contact)) {
// 如果數(shù)據(jù)集合中沒(méi)有這條數(shù)據(jù)就添加進(jìn)去
contacts.push(contact)
}
// 進(jìn)入下一行
resultSet.goToNextRow()
}
// 數(shù)據(jù)整合完畢就釋放資源
resultSet.close()
Logger.info(TAG, 'contacts number is ' + contacts.length)
// 返回整合的聯(lián)系人數(shù)據(jù)
return contacts
}
}
- 數(shù)據(jù)庫(kù)操作:使用[@ohos.data.relationalStore] 接口的getRdbStore獲得一個(gè)相關(guān)的操作型關(guān)系數(shù)據(jù)庫(kù)RdbStore,通過(guò)這個(gè)RdbStore調(diào)用相關(guān)接口進(jìn)行增刪改查,RdbStore.insert數(shù)據(jù)插入,RdbStore.delete數(shù)據(jù)刪除,RdbStore.update更新數(shù)據(jù),RdbStore.query根據(jù)條件查詢(xún)數(shù)據(jù);
- 數(shù)據(jù)同步:RdbStore.on注冊(cè)數(shù)據(jù)庫(kù)觀(guān)察者,使用RdbStore.obtainDistributedTableName根據(jù)本地表名獲取指定遠(yuǎn)程設(shè)備的分布式表名,數(shù)據(jù)發(fā)生變動(dòng)時(shí)通過(guò)RdbStore.sync同步數(shù)據(jù),不需要用時(shí)刪除指定觀(guān)察者使用RdbStore.off。
- 連接設(shè)備管理在RemoteDeviceModel中,源碼參考[RemoteDeviceModel.ets]:
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import deviceManager from '@ohos.distributedDeviceManager';
import Logger from '../model/Logger'
import { BUNDLE } from '../model/RdbConst'
import { BusinessError } from '@ohos.base';
let SUBSCRIBE_ID = 100
const TAG: string = 'RemoteDeviceModel'
class Data {
device: deviceManager.DeviceBasicInfo = {
deviceId: "",
deviceName: "",
deviceType: "",
networkId: "",
}
}
class RemoteDeviceModel {
public deviceList: Array< deviceManager.DeviceBasicInfo > = [];
public discoverList: Array< deviceManager.DeviceBasicInfo > = [];
private callback: () = > void = () = > {};
private authCallback: (device: deviceManager.DeviceBasicInfo) = > void = (device: deviceManager.DeviceBasicInfo) = > '';
private deviceManager: deviceManager.DeviceManager | undefined = undefined
registerDeviceListCallback(callback: () = > void) {
if (typeof (this.deviceManager) !== 'undefined') {
this.registerDeviceListCallbackImplement(callback)
return
}
Logger.info(TAG, 'deviceManager.createDeviceManager begin')
try {
let dmInstance = deviceManager.createDeviceManager(BUNDLE);
Logger.info(TAG, `dmInstance= ${JSON.stringify (dmInstance)}`);
this.deviceManager = dmInstance;
this.registerDeviceListCallbackImplement(callback);
Logger.info(TAG, `createDeviceManager callback returned, value= ${JSON.stringify(this.deviceManager)}`);
} catch (error) {
Logger.error(TAG, `createDeviceManager throw error, code: ${(error as BusinessError).code} message: ${(error as BusinessError).message}`);
}
Logger.info(TAG, 'deviceManager.createDeviceManager end');
}
deviceStateChangeActionOnline(device: deviceManager.DeviceBasicInfo) {
this.deviceList[this.deviceList.length] = device
Logger.info(TAG, `online, device list=${JSON.stringify(this.deviceList)}`)
if (this.authCallback !== undefined) {
this.authCallback(device)
this.authCallback = () = > {}
}
}
deviceStateChangeActionReady(device: deviceManager.DeviceBasicInfo) {
if (this.deviceList.length <= 0) {
this.callback()
return
}
let list: Array< deviceManager.DeviceBasicInfo > = new Array()
for (let i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].deviceId !== device.deviceId) {
list[i] = device
}
}
this.deviceList = list
Logger.info(TAG, `ready, device list=${JSON.stringify(this.deviceList)}`)
this.callback()
}
deviceStateChangeActionOffline(device: deviceManager.DeviceBasicInfo) {
if (this.deviceList.length <= 0) {
this.callback()
return
}
for (let j = 0; j < this.deviceList.length; j++) {
if (this.deviceList[j].deviceId === device.deviceId) {
this.deviceList[j] = device
break
}
}
Logger.info(TAG, `offline, device list=${JSON.stringify(this.deviceList)}`)
}
getLocalDevice(): string {
Logger.info(TAG, `getLocalDevice`);
if(this.deviceManager != undefined) {
let deviceId: string = this.deviceManager.getLocalDeviceId();
Logger.info(TAG, `local deviceInfo=${JSON.stringify(deviceId)}`);
return deviceId;
}
return ''
}
registerDeviceListCallbackImplement(callback: () = > void) {
Logger.info(TAG, 'registerDeviceListCallback' + JSON.stringify(this.deviceManager))
this.callback = callback
if (this.deviceManager === undefined) {
Logger.error(TAG, 'deviceManager has not initialized')
this.callback()
return
}
Logger.info(TAG, 'getTrustedDeviceListSync begin' + JSON.stringify(this.deviceManager));
let list = this.deviceManager.getAvailableDeviceListSync();
Logger.info(TAG, `getTrustedDeviceListSync end, deviceList=${JSON.stringify(list)}`)
if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {
this.deviceList = list
}
this.callback()
Logger.info(TAG, 'callback finished')
this.deviceManager.on('deviceStateChange', (data) = > {
Logger.info(TAG, 'deviceStateChange on:' + JSON.stringify(data));
if (data === null) {
return
}
switch (data.action) {
case deviceManager.DeviceStateChange.UNKNOWN:
this.deviceStateChangeActionOnline(data.device)
break
case deviceManager.DeviceStateChange.AVAILABLE:
this.deviceStateChangeActionReady(data.device)
break
case deviceManager.DeviceStateChange.UNAVAILABLE:
this.deviceStateChangeActionOffline(data.device)
break
default:
break
}
})
this.deviceManager.on('discoverSuccess', (data: Data) = > {
if (data === null) {
return
}
Logger.info(TAG, `discoverSuccess data=${JSON.stringify(data)}`);
this.deviceFound(data);
})
this.deviceManager.on('discoverFailure', (data) = > {
Logger.info(TAG, `discoverFailure data=${JSON.stringify(data)}`);
})
this.deviceManager.on('serviceDie', () = > {
Logger.info(TAG, 'serviceDie')
})
this.startDeviceDiscovery()
}
deviceFound(data: Data) {
if(data != undefined) {
if (data.device != undefined) {
for (let i = 0; i < this.discoverList.length; i++) {
if (this.discoverList[i].deviceId === data.device.deviceId) {
Logger.info(TAG, 'device founded ignored')
return
}
}
this.discoverList[this.discoverList.length] = data.device
Logger.info(TAG, `deviceFound self.discoverList=${JSON.stringify(this.discoverList)}`);
this.callback()
}
}
}
startDeviceDiscovery() {
let discoverParam: Record< string, number > = {
'discoverTargetType': 1
};
let filterOptions: Record< string, number > = {
'availableStatus': 0
};
Logger.info(TAG, `startDeviceDiscovery${SUBSCRIBE_ID}`);
try {
if(this.deviceManager != undefined) {
this.deviceManager.startDiscovering(discoverParam, filterOptions);
}
} catch (error) {
Logger.error(TAG, `startDeviceDiscovery throw error, code: ${(error as BusinessError).code} message: ${(error as BusinessError).message}`);
}
}
unregisterDeviceListCallback() {
if(this.deviceManager != undefined) {
Logger.info(TAG, `stopDeviceDiscovery${SUBSCRIBE_ID}`);
this.deviceManager.stopDiscovering();
this.deviceManager.off('deviceStateChange');
this.deviceManager.off('discoverSuccess');
this.deviceManager.off('discoverFailure');
this.deviceManager.off('serviceDie');
}
this.deviceList = [];
this.discoverList = [];
}
authenticateDevice(device: deviceManager.DeviceBasicInfo, callBack: (device: deviceManager.DeviceBasicInfo) = > void) {
Logger.info(TAG, `bindTarget${JSON.stringify(device)}`);
for (let i = 0; i < this.discoverList.length; i++) {
if (this.discoverList[i].deviceId !== device.deviceId) {
continue
}
if (this.deviceManager === undefined) {
return
}
try {
if (this.deviceManager !== null) {
this.deviceManager.bindTarget(device.deviceId, {
bindType: 1,
targetPkgName: BUNDLE,
appName: 'Distributed distributedrdb',
}, (err, data) = > {
if (err) {
Logger.error(TAG, `authenticateDevice throw error, code: ${(err as BusinessError).code} message: ${(err as BusinessError).message}`);
this.authCallback = () = > {
}
return
}
Logger.debug(TAG, `authenticateDevice succeed: ${JSON.stringify(data)}`);
this.authCallback = callBack;
})
}
} catch (error) {
Logger.error(TAG, `authenticateDevice throw error, code: ${(error as BusinessError).code} message: ${(error as BusinessError).message}`);
}
}
}
}
export default new RemoteDeviceModel()
- 設(shè)備同步:設(shè)備同步數(shù)據(jù)需要[ohos.permission.DISTRIBUTED_DATASYNC] 權(quán)限,在頁(yè)面渲染前申請(qǐng)權(quán)限,源碼參考[Index.ets],
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import data_rdb from '@ohos.data.relationalStore'
import common from '@ohos.app.ability.common'
import Want from '@ohos.app.ability.Want'
import router from '@ohos.router'
import Contact from '../model/Contact'
import ContactDataSource from '../common/BasicDataSource'
import LiteStore from '../model/LiteStore'
import Logger from '../model/Logger'
import RdbModel from '../model/RdbModel'
import { BottomBtn } from '../common/BottomBtn'
import { ContactItem } from '../common/ContactItem'
import { PopupMenu } from '../common/PopupMenu'
import { SyncState } from '../model/LiteStore'
import { SearchBar } from '../common/SearchBar'
import { TitleBar } from '../common/TitleBar'
import { TABLE_NAME, BUNDLE, ABILITY, SQL_CREATE_TABLE, COLUMNS } from '../model/RdbConst'
const TAG: string = 'Index'
export interface stateType {
popupMenu: boolean,
isDistributed: boolean,
isStage: boolean,
selectedIndex: number,
syncState: string,
distributedDevice: string,
opacityValue: number
}
@Entry
@Component
struct Index {
private liteStore = new LiteStore("sync_state", getContext(this) as common.UIAbilityContext)
private rdbModel = new RdbModel(TABLE_NAME, SQL_CREATE_TABLE, COLUMNS, getContext(this) as common.UIAbilityContext)
private intervalId: number = 0
@State contacts: ContactDataSource = new ContactDataSource([])
@State isMultiCheck: boolean = false
@State isSelectedAll: boolean = false
@State state: stateType = {
popupMenu: false,
isDistributed: false,
isStage: false,
selectedIndex: 0,
syncState: SyncState.ManualSync,
distributedDevice: '',
opacityValue: 1
}
async aboutToAppear() {
Logger.info(TAG, 'aboutToAppear')
await this.rdbModel.getRdbStore();
await this.getData();
}
// 拉起應(yīng)用后讀取數(shù)據(jù),暫定為分布式功能
getWant() {
let want = AppStorage.Get< Want >('want') as Want
if(want.parameters != undefined) {
if (this.state.isDistributed && want.parameters.isStage === 'EXIT') {
Logger.info(TAG, 'isStage = EXIT')
this.state.isStage = false
this.state.isDistributed = false
this.state.selectedIndex = 0
this.state.distributedDevice = ''
this.rdbModel.offDataChange()
}
if (!this.state.isDistributed && want.parameters.isStage === 'Stage') {
Logger.info(TAG, 'isStage = Stage')
this.state.isStage = true
this.state.isDistributed = true
this.state.distributedDevice = want.parameters.dmsSrcNetworkId as string;
let context = getContext(this) as common.UIAbilityContext
context.startAbility({
bundleName: BUNDLE,
abilityName: ABILITY,
deviceId: this.state.distributedDevice,
parameters: {
isStage: 'CONNECT'
}
})
Logger.info(TAG, 'onDataChange')
this.rdbModel.onDataChange(this.state.distributedDevice, (result: Array< Contact >)= > {
this.contacts.dataArray = result
this.contacts.notifyDataReload()
})
}
}
}
async onPageShow() {
try {
// 初始化分部署數(shù)據(jù)庫(kù)
await this.rdbModel.getRdbStore()
this.intervalId = setInterval(() = > {
// 手動(dòng)偵聽(tīng)?wèi)?yīng)用被拉起的動(dòng)作
this.getWant()
}, 1000)
// 讀取數(shù)據(jù)庫(kù)數(shù)據(jù)
await this.getData()
} catch (err) {
Logger.error('onPageShow:' + JSON.stringify(err))
}
}
async getData() {
Logger.info(TAG, 'getData')
// 初始化數(shù)據(jù)庫(kù)的表,表名為contact
let predicates = new data_rdb.RdbPredicates(TABLE_NAME)
// 讀取表中的數(shù)據(jù)
this.contacts.replaceDataArray(await this.rdbModel.query(predicates));
// 通知懶加載數(shù)據(jù)變更
this.contacts.notifyDataReload()
Logger.info(TAG, 'getData contacts count' + this.contacts.dataArray.length)
// 讀取Preferences中的數(shù)據(jù)
let syncState = await this.liteStore.getValue()
this.state.syncState = `${syncState}`
if (!this.state.isStage && this.state.isDistributed && syncState === SyncState.AutomaticSync) {
await this.syncData()
}
}
showDeleteDialog() {
let deleteContacts: Contact[] = []
this.contacts.dataArray.forEach((contact) = > {
if (contact.isSelected) {
deleteContacts.push(contact)
}
})
if (deleteContacts.length == 0) {
return
}
AlertDialog.show({
message: $r('app.string.delete_contact'),
primaryButton: {
value: $r('app.string.sure'),
fontColor: Color.Red,
action: async () = > {
await this.rdbModel.deleteContacts(deleteContacts)
await this.getData()
this.quitMultiCheck()
}
},
secondaryButton: {
value: $r('app.string.cancel'),
fontColor: Color.Blue,
action: () = > {
}
}
})
}
handleClickContact(item: Contact, index: number) {
Logger.info(TAG, `handleClickContact, item = ${JSON.stringify(item)}`)
if (this.isMultiCheck) {
let tempContacts = this.contacts.dataArray
this.contacts.dataArray = []
tempContacts[index].isSelected = !item.isSelected
this.contacts.dataArray = tempContacts
this.contacts.notifyDataReload()
} else {
router.pushUrl({
url: 'pages/ContactEdit',
params: { contact: item, isInsert: false }
})
}
}
refreshSelectState(isSelect: boolean) {
this.contacts.dataArray.forEach((contact) = > {
contact.isSelected = isSelect
})
this.contacts.notifyDataReload()
}
quitMultiCheck() {
this.isSelectedAll = false
this.refreshSelectState(this.isSelectedAll)
this.isMultiCheck = false
}
handleBottomBtnClick = (index: number) = > {
switch (index) {
case 0:
this.isSelectedAll = !this.isSelectedAll
this.refreshSelectState(this.isSelectedAll)
break
case 1:
this.showDeleteDialog()
break
case 2:
this.quitMultiCheck()
break
default:
break
}
}
handleRightBtn = () = > {
this.state.popupMenu = true;
this.state.opacityValue = 1;
}
syncData = () = > {
Logger.info(TAG, 'sync data')
let predicates = new data_rdb.RdbPredicates(TABLE_NAME)
predicates.inAllDevices()
this.rdbModel.syncData(predicates)
}
build() {
Stack({ alignContent: Alignment.BottomEnd }) {
Column() {
Stack() {
if (this.state.isStage) {
TitleBar()
} else {
TitleBar({ rightBtn: $r('app.media.more'), handleRightBtn: this.handleRightBtn })
}
if (this.state.isDistributed && !this.state.isStage && this.state.syncState === SyncState.ManualSync) {
Row() {
Blank()
Image($r('app.media.ic_syncto'))
.size({ width: 50, height: 60 })
.onClick(this.syncData)
}.width('80%')
}
}.width('100%')
SearchBar()
List() {
LazyForEach(this.contacts, (item: Contact, index) = > {
ListItem() {
ContactItem({ contact: item, isMultiCheck: $isMultiCheck })
}
.onClick(() = > {
this.handleClickContact(item, index)
})
}, (item: Contact) = > JSON.stringify(item))
}
.width('100%')
.layoutWeight(1)
.padding({ left: 10, right: 10 })
.divider({ strokeWidth: 1, color: Color.Gray, startMargin: 16, endMargin: 16 })
}
.width('100%')
.height('100%')
if (this.state.popupMenu) {
PopupMenu({ state: $state, handleStartAbility: this.syncData })
}
BottomBtn({
isMultiCheck: this.isMultiCheck,
isSelectedAll: this.isSelectedAll,
handleBottomBtnClick: this.handleBottomBtnClick
})
if (!this.isMultiCheck && !this.state.isStage) {
Button() {
Image($r('app.media.add'))
.height('100%')
.width('100%')
.objectFit(ImageFit.Contain)
.align(Alignment.End)
}
.id('btnAdd')
.width(80)
.height(80)
.margin({ right: 20, bottom: 50 })
.type(ButtonType.Circle)
.backgroundColor('#0D9FFB')
.onClick(() = > {
Logger.info(TAG, 'onClick')
router.pushUrl({
url: 'pages/ContactEdit',
params: { contact: new Contact(0, '', 0, '', -1, ''), isInsert: true }
})
})
}
}
.width('100%')
.height('100%')
}
onBackPress() {
Logger.info(TAG, 'onBackPress')
let context = getContext(this) as common.UIAbilityContext
context.startAbility({
bundleName: BUNDLE,
abilityName: ABILITY,
deviceId: this.state.distributedDevice,
parameters: {
isStage: 'EXIT'
}
})
this.rdbModel.offDataChange()
}
onPageHide() {
Logger.info(TAG, 'onBackPress')
clearInterval(this.intervalId)
}
}
使用[@ohos.distributedDeviceManager]接口,首先通過(guò)createDeviceManager創(chuàng)建設(shè)備管理器實(shí)例,然后通過(guò)getTrustedDeviceListSync同步獲取所有可信設(shè)備列表;
- 設(shè)備連接:首先通過(guò)on方法注冊(cè)設(shè)備狀態(tài),例如發(fā)現(xiàn)設(shè)備,設(shè)備連接失敗,然后通過(guò)startDeviceDiscovery方法發(fā)現(xiàn)周邊設(shè)備,然后選擇連接設(shè)備,再用[startAbility]啟動(dòng)連接設(shè)備的應(yīng)用。
審核編輯 黃宇
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。
舉報(bào)投訴
-
數(shù)據(jù)庫(kù)
+關(guān)注
關(guān)注
7文章
4020瀏覽量
68373 -
分布式
+關(guān)注
關(guān)注
1文章
1094瀏覽量
76588 -
鴻蒙
+關(guān)注
關(guān)注
60文章
2964瀏覽量
45938 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2153瀏覽量
36077 -
OpenHarmony
+關(guān)注
關(guān)注
33文章
3954瀏覽量
21128
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
熱點(diǎn)推薦
TiDB分布式數(shù)據(jù)庫(kù)運(yùn)維實(shí)踐
TiDB 是 PingCAP 開(kāi)發(fā)的開(kāi)源分布式關(guān)系型數(shù)據(jù)庫(kù),兼容 MySQL 5.7 協(xié)議,底層存儲(chǔ)基于 TiKV(
Oracle數(shù)據(jù)庫(kù)ASM實(shí)例無(wú)法掛載的數(shù)據(jù)恢復(fù)案例
一個(gè)Oracle數(shù)據(jù)庫(kù)故障表現(xiàn)為ASM磁盤(pán)組掉線(xiàn),ASM實(shí)例無(wú)法掛載(mount)。數(shù)據(jù)庫(kù)管理員自行進(jìn)行簡(jiǎn)單修復(fù),未能成功,隨后聯(lián)系北亞數(shù)據(jù)恢復(fù)中心恢復(fù)
分布式數(shù)據(jù)恢復(fù)—Ceph+TiDB數(shù)據(jù)恢復(fù)報(bào)告
無(wú)法正常訪(fǎng)問(wèn)。目標(biāo)需要恢復(fù)的RBD卷中存儲(chǔ)了一臺(tái)虛擬機(jī)的完整磁盤(pán)鏡像,該虛擬機(jī)內(nèi)部運(yùn)行TiDB分布式數(shù)據(jù)庫(kù)系統(tǒng),包含重要的業(yè)務(wù)數(shù)據(jù)。
SC-3568HA:解鎖鴻蒙全權(quán)限API與分布式能力的工業(yè)控制平臺(tái)
傳統(tǒng)嵌入式開(kāi)發(fā)面臨硬件碎片化、高權(quán)限功能缺失、分布式協(xié)同復(fù)雜及自動(dòng)化測(cè)試不足等痛點(diǎn)。SC-3568HA開(kāi)發(fā)板基于鴻蒙系統(tǒng),通過(guò)統(tǒng)一內(nèi)核抽象層和硬件驅(qū)動(dòng)框架解決兼容問(wèn)題,開(kāi)放全量系統(tǒng)AP
一鍵部署無(wú)損網(wǎng)絡(luò):EasyRoCE助力分布式存儲(chǔ)效能革命
分布式存儲(chǔ)的性能瓶頸往往在于網(wǎng)絡(luò)。如何構(gòu)建一個(gè)高帶寬、超低時(shí)延、零丟包的無(wú)損網(wǎng)絡(luò),是釋放分布式存儲(chǔ)全部潛力、賦能企業(yè)關(guān)鍵業(yè)務(wù)(如實(shí)時(shí)數(shù)據(jù)庫(kù)、AI訓(xùn)練、高性能計(jì)算)的關(guān)鍵挑戰(zhàn)。
【HarmonyOS 5】金融應(yīng)用開(kāi)發(fā)鴻蒙組件實(shí)踐
【HarmonyOS 5】金融應(yīng)用開(kāi)發(fā)鴻蒙組件實(shí)踐 ##鴻蒙開(kāi)發(fā)能力 ##HarmonyOS S
【 HarmonyOS 5 入門(mén)系列 】鴻蒙HarmonyOS示例項(xiàng)目講解
【 HarmonyOS 5 入門(mén)系列 】鴻蒙HarmonyOS示例項(xiàng)目講解 ##鴻蒙開(kāi)發(fā)能力 ##Har
鴻蒙5開(kāi)發(fā)寶藏案例分享---應(yīng)用接續(xù)提升內(nèi)容發(fā)布體驗(yàn)
小紅書(shū)圖文,突然想換平板繼續(xù)排版,這時(shí)候只要輕點(diǎn)平板Dock欄圖標(biāo),草稿瞬間帶著圖片文字無(wú)縫轉(zhuǎn)移!這種科幻片般的體驗(yàn),用HarmonyOS的分布式能力分分鐘就能實(shí)現(xiàn)!
(悄悄說(shuō):實(shí)測(cè)中甚至可以實(shí)現(xiàn)手機(jī)
發(fā)表于 06-03 18:25
鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(游戲)
十年前藏的現(xiàn)金一樣驚喜?。┻@些藏在文檔深處的\"武功秘籍\",能幫我們輕松實(shí)現(xiàn)分布式游戲、跨端協(xié)同這些聽(tīng)起來(lái)很酷的功能??焐宪?chē),帶你解鎖鴻蒙開(kāi)發(fā)的正確姿勢(shì)!
一、分布式游戲手柄
發(fā)表于 06-03 18:22
鴻蒙5開(kāi)發(fā)寶藏案例分享---一多開(kāi)發(fā)實(shí)例(旅行訂票)
: breakpoint === \'sm\' ? 80 : 20
})
黑科技功能 :
上滑自動(dòng)隱藏篩選欄(手機(jī)專(zhuān)屬)
跨設(shè)備訂單同步(通過(guò)分布式能力)
實(shí)時(shí)價(jià)格波動(dòng)可視化圖表
?** 開(kāi)發(fā)避坑指南
發(fā)表于 06-03 16:16
SQLSERVER數(shù)據(jù)庫(kù)是什么
SQL Server 是由微軟公司開(kāi)發(fā)的一款 關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS) ,用于存儲(chǔ)、管理和檢索結(jié)構(gòu)化數(shù)據(jù)。它是企業(yè)級(jí)應(yīng)用中廣泛使用
MySQL數(shù)據(jù)庫(kù)是什么
MySQL數(shù)據(jù)庫(kù)是一種 開(kāi)源的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS) ,由瑞典MySQL AB公司開(kāi)發(fā),后被Oracle公司收購(gòu)。它通過(guò)結(jié)構(gòu)化查
HarmonyOS5云服務(wù)技術(shù)分享--云數(shù)據(jù)庫(kù)使用指南
? 華為云數(shù)據(jù)庫(kù)(CloudDB)在HarmonyOS中的使用指南 ?
??嗨,開(kāi)發(fā)者朋友們!??
今天咱們來(lái)聊聊華為云數(shù)據(jù)庫(kù)(CloudDB)在H
發(fā)表于 05-22 18:29
分布式存儲(chǔ)數(shù)據(jù)恢復(fù)—虛擬機(jī)上hbase和hive數(shù)據(jù)庫(kù)數(shù)據(jù)恢復(fù)案例
分布式存儲(chǔ)數(shù)據(jù)恢復(fù)環(huán)境:
16臺(tái)某品牌R730xd服務(wù)器節(jié)點(diǎn),每臺(tái)服務(wù)器節(jié)點(diǎn)上有數(shù)臺(tái)虛擬機(jī)。
虛擬機(jī)上部署Hbase和Hive數(shù)據(jù)庫(kù)。
分布式存儲(chǔ)故障:
“RdbStore”上線(xiàn)開(kāi)源鴻蒙社區(qū) 助力鴻蒙應(yīng)用數(shù)據(jù)訪(fǎng)問(wèn)效率大幅提升
近日,由伙伴參與共建的鴻蒙關(guān)系映射數(shù)據(jù)庫(kù)“RdbStore”正式上線(xiàn)OpenHarmony社區(qū),為鴻蒙生態(tài)開(kāi)發(fā)者提供了簡(jiǎn)單高效的
鴻蒙HarmonyOS開(kāi)發(fā)實(shí)例:【分布式關(guān)系型數(shù)據(jù)庫(kù)】
評(píng)論