data-sync-of-distributed-data-object.md 17.6 KB
Newer Older
A
Annie_wang 已提交
1 2 3 4 5
# Cross-Device Synchronization of Distributed Data Objects


## When to Use

A
Annie_wang 已提交
6
The traditional implementation of data synchronization between devices involves heavy workload. You need to design the message processing logic for setting up a communication link, sending, receiving, and processing messages, and resolving data conflicts, as well as retry mechanism upon errors. In addition, the debugging complexity increases with the number of devices.
A
Annie_wang 已提交
7

A
Annie_wang 已提交
8
The device status, message sending progress, and data transmitted are variables. If these variables support global access, they can be accessed as local variables by difference devices. This simplifies data synchronization across devices.
A
Annie_wang 已提交
9

A
Annie_wang 已提交
10
The distributed data object (**distributedDataObject**) module implements global access to variables. It provides basic data object management capabilities, including creating, querying, deleting, and modifying in-memory objects and subscribing to data or status changes. It also provides distributed capabilities. OpenHarmony provides easy-to-use JS APIs for distributed application scenarios. With these APIs, you can easily implement data collaboration for an application across devices and listening for status and data changes between devices. The **distributedDataObject** module implements data object collaboration for the same application across multiple devices that form a Super Device. It greatly reduces the development workloads compared with the traditional implementation.
A
Annie_wang 已提交
11 12 13 14


## Basic Concepts

A
Annie_wang 已提交
15 16 17 18
- Distributed in-memory database
  

The distributed in-memory database caches data in the memory so that applications can quickly access data without persisting data. If the database is closed, the data is not retained.
A
Annie_wang 已提交
19 20

- Distributed data object
A
Annie_wang 已提交
21
  
A
Annie_wang 已提交
22

A
Annie_wang 已提交
23
A distributed data object is an encapsulation of the JS object type. Each distributed data object instance creates a data table in the in-memory database. The in-memory databases created for different applications are isolated from each other. Reading and writing a distributed data object are mapped to the **get** and **put** operations in the corresponding database, respectively.
A
Annie_wang 已提交
24

A
Annie_wang 已提交
25 26 27 28 29
The distributed data object has the following states in its lifecycle:

  - **Uninitialized**: The distributed data object is not instantiated or is destroyed.
  - **Local**: A data table is created, but the data cannot be synchronized.
  - **Distributed**: A data table is created, and data can be synchronized (there are at least two online devices with the same session ID). If a device is offline or the session ID is empty, the distributed data object changes to the local state.
A
Annie_wang 已提交
30 31 32 33 34 35 36 37


## Working Principles

**Figure 1** Working mechanism

![distributedObject](figures/distributedObject.jpg)

A
Annie_wang 已提交
38
The distributed data objects are encapsulated JS objects in distributed in-memory databases, and can be operated in the same way as local variables. The system automatically implements data synchronization across devices.
A
Annie_wang 已提交
39 40


A
Annie_wang 已提交
41
### Encapsulation and Storage of JS Objects
A
Annie_wang 已提交
42 43 44

- An in-memory database is created for each distributed data object instance and identified by a session ID (**SessionId**). The in-memory databases created for different applications are isolated from each other.

A
Annie_wang 已提交
45
- When a distributed data object is instantiated, all properties of the object are traversed recursively. **Object.defineProperty** is used to define the **set()** and **get()** methods for all properties. The **set()** and **get()** methods correspond to the **put** and **get** operations of a record in the database, respectively. **Key** specifies the property name, and **Value** specifies the property value.
A
Annie_wang 已提交
46

A
Annie_wang 已提交
47
- When a distributed data object is read or written, the **get()** or **set()** method is automatically called to perform the related operation on data in the database.
A
Annie_wang 已提交
48 49

**Table 1** Correspondence between a distributed data object and a distributed database
A
Annie_wang 已提交
50 51

| Distributed Data Object Instance| Object Instance| Property Name| Property Value|
A
Annie_wang 已提交
52
| -------- | -------- | -------- | -------- |
A
Annie_wang 已提交
53
| Distributed in-memory database| Database identified by **sessionID**| Key of a record in the database| Value of a record in the database|
A
Annie_wang 已提交
54 55


A
Annie_wang 已提交
56
### Cross-Device Synchronization and Data Change Notification
A
Annie_wang 已提交
57

A
Annie_wang 已提交
58
One of the most important functions of distributed data objects is to implement data synchronization between objects. Distributed data objects are created locally for the devices on a trusted network. If the distributed data objects on different devices are set with the same **sessionID**, data can be synchronized between them.
A
Annie_wang 已提交
59

A
Annie_wang 已提交
60
As shown in the following figure, distributed data object 1 of device A and distributed data object 1 of device B are set with the same session ID **session1**, and synchronization relationship of session 1 is established between the two objects.
A
Annie_wang 已提交
61

A
Annie_wang 已提交
62
**Figure 2** Object synchronization relationship 
A
Annie_wang 已提交
63 64 65

![distributedObject_sync](figures/distributedObject_sync.jpg)

A
Annie_wang 已提交
66 67 68
For each device, only one distributed data object can be added to a synchronization relationship. As shown in the preceding figure, distributed data object 2 of device A cannot be added to session 1 because distributed data object 1 of device A has been added to session 1.

After the synchronization relationship is established, each session has a copy of shared object data. The distributed data objects added to a session support the following operations:
A
Annie_wang 已提交
69

A
Annie_wang 已提交
70
- Reading or modifying the data in the session.
A
Annie_wang 已提交
71

A
Annie_wang 已提交
72
- Listening for data changes made by other devices.
A
Annie_wang 已提交
73

A
Annie_wang 已提交
74
- Listening for status changes, such as the addition and removal of other devices.
A
Annie_wang 已提交
75 76 77



A
Annie_wang 已提交
78
### Minimum Synchronization Unit
A
Annie_wang 已提交
79

A
Annie_wang 已提交
80
Property is the minimum unit to synchronize in distributed data objects. For example, object 1 in the following figure has three properties: name, age, and parents. If one of the properties is changed, only the changed attribute needs to be synchronized.
A
Annie_wang 已提交
81 82

**Figure 3** Synchronization of distributed data objects
A
Annie_wang 已提交
83

A
Annie_wang 已提交
84 85 86 87

![distributedObject_syncView](figures/distributedObject_syncView.jpg)


A
Annie_wang 已提交
88
### Persistence of Distributed Data Objects
A
Annie_wang 已提交
89

A
Annie_wang 已提交
90
Distributed data objects run in the process space of applications. After the data of a distributed data object is persisted in the distributed database, the data will not be lost after the application exits.
A
Annie_wang 已提交
91 92 93

You need to persist distributed data objects in the following scenarios:

A
Annie_wang 已提交
94
- Enable an application to retrieve the exact same data after it starts again. In this case, you need to persist the distributed data object (for example, object 1 with session ID 1). After the application starts again, create a distributed data object (for example, object 2) and set the session ID to 1. Then, the application can retrieve the data of object 1.
A
Annie_wang 已提交
95

A
Annie_wang 已提交
96
- Enable an application started on another device to retrieve the exact same data. In this case, you need to persist the distributed data object (for example, object 1 with session ID 1) on device A and synchronize the data to device B. Then, create a distributed data object (for example, object 2) and set the session ID to 1. When the application is started on device B, it can retrieve the same application data used on device A before the application is closed.
A
Annie_wang 已提交
97 98 99 100


## Constraints

A
Annie_wang 已提交
101
- Only the data of the same application can be synchronized across devices, that is, the devices must have the same **bundleName**.
A
Annie_wang 已提交
102

A
Annie_wang 已提交
103
- Data can be synchronized for the distributed data objects with the same session ID.
A
Annie_wang 已提交
104 105 106 107 108

- Each distributed data object occupies 100 KB to 150 KB of memory. Therefore, you are advised not to create too many distributed data objects.

- The maximum size of a distributed data object is 500 KB.

A
Annie_wang 已提交
109
- If data of 1 KB data is modified on device A, device B can complete data update within 50 ms after receiving a data change notification.
A
Annie_wang 已提交
110 111 112

- A maximum of 16 distributed data object instances can be created for an application.

A
Annie_wang 已提交
113
- For the sake of performance and user experience, the maximum number of devices for data collaboration is 3.
A
Annie_wang 已提交
114

A
Annie_wang 已提交
115
- For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified.
A
Annie_wang 已提交
116

A
Annie_wang 已提交
117
- Currently, only JS APIs are supported.
A
Annie_wang 已提交
118 119 120 121


## Available APIs

A
Annie_wang 已提交
122
Most of the APIs for cross-device synchronization of distributed data objects are executed asynchronously in callback or promise mode. The following table uses the callback-based APIs as an example. For more information about the APIs, see [Distributed Data Object](../reference/apis/js-apis-data-distributedobject.md).
A
Annie_wang 已提交
123

A
Annie_wang 已提交
124
| API| Description|
A
Annie_wang 已提交
125
| -------- | -------- |
A
Annie_wang 已提交
126 127 128 129 130 131 132 133
| create(context: Context, source: object): DataObject | Creates a distributed data object instance.|
| genSessionId(): string | Generates a session ID for distributed data objects.|
| setSessionId(sessionId: string, callback: AsyncCallback<void>): void | Sets a session ID for data synchronization. Automatic synchronization is performed for devices with the same session ID on a trusted network.|
| setSessionId(callback: AsyncCallback<void>): void | Exits all sessions.|
| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array<string> }>): void | Subscribes to data changes of this distributed data object.|
| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | Subscribes to status changes of this distributed data object.|
| save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void | Saves a distributed data object.|
| revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void | Revokes the saving of the distributed data object.|
A
Annie_wang 已提交
134 135 136 137


## How to Develop

A
Annie_wang 已提交
138
The following example demonstrates how to implement synchronization of distributed data objects.
A
Annie_wang 已提交
139 140

1. Import the **@ohos.data.distributedDataObject** module.
A
Annie_wang 已提交
141
   
A
Annie_wang 已提交
142 143 144 145
   ```js
   import distributedDataObject from '@ohos.data.distributedDataObject';
   ```

A
Annie_wang 已提交
146
2. Apply for required permissions.
A
Annie_wang 已提交
147

A
Annie_wang 已提交
148
   1. Apply for the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
A
Annie_wang 已提交
149 150
   2. Display a dialog box to ask authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/accesstoken-guidelines.md#requesting-user-authorization).

A
Annie_wang 已提交
151
3. Create a distributed data object instance.
A
Annie_wang 已提交
152 153

   Stage model:
A
Annie_wang 已提交
154
   
A
Annie_wang 已提交
155 156 157 158
   ```js
   // Import the module.
   import distributedDataObject from '@ohos.data.distributedDataObject';
   import UIAbility from '@ohos.app.ability.UIAbility';
A
Annie_wang 已提交
159 160 161 162 163 164 165 166 167 168
   import { BusinessError } from '@ohos.base';
   import window from '@ohos.window';

   interface sourceObject{
     name: string,
     age: number,
     isVis: boolean
     parent: { [key: string]: string },
     list: { [key: string]: string }[]
   }
A
Annie_wang 已提交
169
   class EntryAbility extends UIAbility {
A
Annie_wang 已提交
170 171
     onWindowStageCreate(windowStage: window.WindowStage) {
       let source: sourceObject = {
A
Annie_wang 已提交
172 173 174 175 176
         name: 'jack',
         age: 18,
         isVis: false,
         parent: { mother: 'jack mom', father: 'jack Dad' },
         list: [{ mother: 'jack mom' }, { father: 'jack Dad' }]
A
Annie_wang 已提交
177 178
       }
       let localObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, source);
A
Annie_wang 已提交
179 180 181 182 183 184
     }
   }
   ```

   FA model:

A
Annie_wang 已提交
185
   
A
Annie_wang 已提交
186 187 188 189 190 191
   ```js
   // Import the module.
   import distributedDataObject from '@ohos.data.distributedDataObject';
   import featureAbility from '@ohos.ability.featureAbility';
   // Obtain the context.
   let context = featureAbility.getContext();
A
Annie_wang 已提交
192 193 194 195 196 197 198 199
   interface sourceObject{
     name: string,
     age: number,
     isVis: boolean
     parent: { [key: string]: string },
     list: { [key: string]: string }[]
   }
   let source: sourceObject = {
A
Annie_wang 已提交
200 201 202 203 204
     name: 'jack',
     age: 18,
     isVis: false,
     parent: { mother: 'jack mom', father: 'jack Dad' },
     list: [{ mother: 'jack mom' }, { father: 'jack Dad' }]
A
Annie_wang 已提交
205 206 207
   }
   // Create a distributed data object, which has properties of the string, number, boolean, and object types.
   let localObject: distributedDataObject.DataObject = distributedDataObject.create(context, source);
A
Annie_wang 已提交
208 209 210
   ```

4. Set the same session ID for the distributed data objects for data synchronization. The data objects in the synchronization network include the local and remote objects.
A
Annie_wang 已提交
211
   
A
Annie_wang 已提交
212 213
   ```js
   // Set a session ID, for example, 123456, for device 1.
A
Annie_wang 已提交
214
   let sessionId: string = '123456';
A
Annie_wang 已提交
215 216 217 218 219
   
   localObject.setSessionId(sessionId);
   
   // Set the same session ID for device 2.
   
A
Annie_wang 已提交
220 221
   // Create a distributed data object, which has properties of the string, number, boolean, and object types.
   let remoteSource: sourceObject = {
A
Annie_wang 已提交
222 223 224 225 226
     name: undefined,
     age: undefined, // undefined indicates that the data comes from the peer end.
     isVis: true,
     parent: undefined,
     list: undefined
A
Annie_wang 已提交
227 228 229
   }
   let remoteObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, remoteSource);
   // After learning that the device goes online, the remote object synchronizes data. That is, name is changed to jack and age to 18.
A
Annie_wang 已提交
230 231 232 233 234
   remoteObject.setSessionId(sessionId);
   ```

5. Observe data changes of a distributed data object. You can subscribe to data changes of the remote object. When the data in the remote object changes, a callback will be invoked to return a data change event.
   
A
Annie_wang 已提交
235 236 237 238
   ```js
   interface ChangeCallback {
     sessionId: string,
     fields: Array<string> 
A
Annie_wang 已提交
239 240
   }
   
A
Annie_wang 已提交
241 242 243 244 245 246 247 248
   localObject.on("change", (changeData:ChangeCallback) => {
     console.info("change" + changeData.sessionId);
     if (changeData.fields != null && changeData.fields != undefined) {
       for (let index: number = 0; index < changeData.fields.length; index++) {
         console.info(`The element ${localObject[changeData.fields[index]]} changed.`);
       }
     }
   });
A
Annie_wang 已提交
249 250
   ```

A
Annie_wang 已提交
251 252
6. Modify properties of the distributed data object. The object properties support basic data types (number, Boolean, and string) and complex data types (array and nested basic types).
   
A
Annie_wang 已提交
253 254 255 256 257 258 259 260 261 262
   ```js
   localObject.name = 'jack1';
   localObject.age = 19;
   localObject.isVis = false;
   localObject.parent = { mother: 'jack1 mom', father: 'jack1 Dad' };
   localObject.list = [{ mother: 'jack1 mom' }, { father: 'jack1 Dad' }];
   ```

   > **NOTE**
   >
A
Annie_wang 已提交
263
   > For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified.
A
Annie_wang 已提交
264

A
Annie_wang 已提交
265
   
A
Annie_wang 已提交
266 267 268 269 270 271 272
   ```js
   // Supported modification.
   localObject.parent = { mother: 'mom', father: 'dad' };
   // Modification not supported.
   localObject.parent.mother = 'mom';
   ```

A
Annie_wang 已提交
273 274
7. Access a distributed data object. Obtain the distributed data object properties, which are the latest data on the network.
   
A
Annie_wang 已提交
275 276 277 278
   ```js
   console.info(`name:${localObject['name']}`); 
   ```

A
Annie_wang 已提交
279 280
8. Unsubscribe from data changes. You can specify the callback to unregister. If you do not specify the callback, this API unregisters all data change callbacks of the distributed data object.
   
A
Annie_wang 已提交
281 282
   ```js
   // Unregister this.changeCallback.
A
Annie_wang 已提交
283 284 285 286 287 288 289 290
   localObject.off('change',(changeData: ChangeCallback) => {
     console.info("change" + changeData.sessionId);
     if (changeData.fields != null && changeData.fields != undefined) {
       for (let index: number = 0; index < changeData.fields.length; index++) {
         console.info("changed !" + changeData.fields[index] + " " + g_object[changeData.fields[index]]);
       }
     }
   });
A
Annie_wang 已提交
291 292 293 294
   // Unregister all data change callbacks. 
   localObject.off('change'); 
   ```

A
Annie_wang 已提交
295 296
9. Subscribe to status changes of a distributed data object. A callback will be invoked to report the status change when the target distributed data object goes online or offline.
   
A
Annie_wang 已提交
297
   ```js
A
Annie_wang 已提交
298 299 300 301
   interface onStatusCallback {
     sessionId: string,
     networkId: string,
     status: 'online' | 'offline'
A
Annie_wang 已提交
302 303
   }
   
A
Annie_wang 已提交
304 305 306 307
   localObject.on('status', (statusCallback: onStatusCallback) => {
     console.info("status changed " + statusCallback.sessionId + " " + statusCallback.status + " " +  statusCallback.networkId);
     // Service processing.
   });
A
Annie_wang 已提交
308 309
   ```

A
Annie_wang 已提交
310 311
10. Save a distributed data object and revoke the data saved.
    
A
Annie_wang 已提交
312 313
    ```js
    // Save the data object if the device on the network needs to retrieve the object data after the application exits.
A
Annie_wang 已提交
314
    localObject.save("local").then((result: distributedDataObject.SaveSuccessResponse) => {
A
Annie_wang 已提交
315
      console.info(`Succeeded in saving. SessionId:${result.sessionId},version:${result.version},deviceId:${result.deviceId}`);
A
Annie_wang 已提交
316
    }).catch((err: BusinessError) => {
A
Annie_wang 已提交
317 318
      console.error(`Failed to save. Code:${err.code},message:${err.message}`);
    });
A
Annie_wang 已提交
319 320 321
      
    // Revoke the data saved.
    localObject.revokeSave().then((result: distributedDataObject.RevokeSaveSuccessResponse) => {
A
Annie_wang 已提交
322
      console.info(`Succeeded in revokeSaving. Session:${result.sessionId}`);
A
Annie_wang 已提交
323
    }).catch((err: BusinessError) => {
A
Annie_wang 已提交
324 325 326 327 328
      console.error(`Failed to revokeSave. Code:${err.code},message:${err.message}`);
    });
    ```

11. Unsubscribe from the status changes of a distributed data object. You can specify the callback to unregister. If you do not specify the callback, this API unregisters all status change callbacks of this distributed data object.
A
Annie_wang 已提交
329
    
A
Annie_wang 已提交
330
    ```js
A
Annie_wang 已提交
331 332 333 334 335
    interface offStatusCallback {
      sessionId: string,
      deviceId: string,
      status: 'online' | 'offline'
    }
A
Annie_wang 已提交
336
    // Unregister this.statusCallback.
A
Annie_wang 已提交
337 338 339 340
    localObject.off('status', (statusCallback: offStatusCallback) => {
      console.info("status changed " + statusCallback.sessionId + " " + statusCallback.status + " " + statusCallback.deviceId);
      // Service processing.
    });
A
Annie_wang 已提交
341 342 343 344 345
    // Unregister all status change callbacks.
    localObject.off('status');
    ```

12. Remove a distributed data object from the synchronization network. The data of the removed distributed data object will not be synchronized to other devices.
A
Annie_wang 已提交
346
    
A
Annie_wang 已提交
347 348
    ```js
    localObject.setSessionId(() => {
A
Annie_wang 已提交
349
      console.info('leave all session.');
A
Annie_wang 已提交
350
    });
A
Annie_wang 已提交
351
    ```