1e41f4b71Sopenharmony_ci# Cross-Device Sync of Distributed Data Objects 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ci## When to Use 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ciThe traditional implementation of data sync 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. 7e41f4b71Sopenharmony_ci 8e41f4b71Sopenharmony_ciThe 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 sync across devices. 9e41f4b71Sopenharmony_ci 10e41f4b71Sopenharmony_ciThe 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. 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ciCurrently, <!--RP2-->distributed data objects can be used only in [cross-device migration](../application-models/hop-cross-device-migration.md) and [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).<!--RP2End--> 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci## Basic Concepts 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci- Distributed in-memory database<br> 17e41f4b71Sopenharmony_ci 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. 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci- Distributed data object<br> 20e41f4b71Sopenharmony_ci 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. 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci The distributed data object has the following states in its lifecycle: 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci - **Uninitialized**: The distributed data object is not instantiated or is destroyed. 25e41f4b71Sopenharmony_ci - **Local**: A data table is created, but the data cannot be synced. 26e41f4b71Sopenharmony_ci - **Distributed**: A data table is created, and data can be synced (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. 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci## Working Principles 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci**Figure 1** Working mechanism 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ciThe 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 sync across devices. 36e41f4b71Sopenharmony_ci 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci### Encapsulation and Storage of JS Objects 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci- 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. 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci- 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. 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci- 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. 45e41f4b71Sopenharmony_ci 46e41f4b71Sopenharmony_ci**Table 1** Correspondence between a distributed data object and a distributed database 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci| Distributed Data Object Instance| Object Instance| Property Name| Property Value| 49e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | 50e41f4b71Sopenharmony_ci| Distributed in-memory database| Database identified by **sessionID**| Key of a record in the database| Value of a record in the database| 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci### Cross-Device Sync and Data Change Notification 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ciOne of the most important functions of distributed data objects is to implement data sync 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 synced between them. 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ciAs 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 sync relationship of session 1 is established between the two objects. 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci **Figure 2** Object sync relationship 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci 63e41f4b71Sopenharmony_ciFor each device, only one distributed data object can be added to a sync 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. 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ciAfter the sync relationship is established, each session has a copy of shared object data. The distributed data objects added to a session support the following operations: 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci- Reading or modifying the data in the session. 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci- Listening for data changes made by other devices. 70e41f4b71Sopenharmony_ci 71e41f4b71Sopenharmony_ci- Listening for status changes, such as the addition and removal of other devices. 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ciWhen a distributed data object is added to a session, if its data is different from that of the session, the distributed data object updates data of the session. If you do not want to update the data of the session when adding a distributed data object to a session and obtain the data of the session, set the attribute value of the object to **undefined** (for an asset, set each attribute of the asset to an empty string). 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci### Minimum Sync Unit 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ciProperty 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 property needs to be synced. 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ciThe object properties support basic types (number, Boolean, and string) and complex types (array and nested basic types). For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified. 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ci```ts 82e41f4b71Sopenharmony_cidataObject['parents'] = {mom: "amy"}; // Supported modification 83e41f4b71Sopenharmony_cidataObject['parents']['mon'] = "amy"; // Unsupported modification 84e41f4b71Sopenharmony_ci``` 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci**Figure 3** Sync of distributed data objects 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci### Persistence of Distributed Data Objects 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ciDistributed 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. 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ciYou need to persist distributed data objects in the following scenarios: 97e41f4b71Sopenharmony_ci 98e41f4b71Sopenharmony_ci- 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. 99e41f4b71Sopenharmony_ci 100e41f4b71Sopenharmony_ci- 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. 101e41f4b71Sopenharmony_ci 102e41f4b71Sopenharmony_ci### Asset Sync Mechanism 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ciIn a distributed object, [asset](../reference/apis-arkdata/js-apis-data-commonType.md#asset) is used to describe a local entity asset file. When the distributed object is synced across devices, the file is also synced to other devices with it. Currently, only asset is supported. The type [assets](../reference/apis-arkdata/js-apis-data-commonType.md#assets) is not supported. To synchronize multiple assets, use each asset as a root property of the distributed object. 105e41f4b71Sopenharmony_ci 106e41f4b71Sopenharmony_ci## Constraints 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci- Currently, <!--RP2-->distributed data objects can be used only in [cross-device migration](../application-models/hop-cross-device-migration.md) and [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).<!--RP2End--> 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci- Only the data of the same application can be synced across devices, that is, the devices must have the same **bundleName**. 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci- Data can be synced for the distributed data objects with the same session ID. 113e41f4b71Sopenharmony_ci 114e41f4b71Sopenharmony_ci- Each distributed data object occupies 100 KB to 150 KB of memory. Therefore, you are advised not to create too many distributed data objects. 115e41f4b71Sopenharmony_ci 116e41f4b71Sopenharmony_ci- The maximum size of a distributed data object is 500 KB. 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci- 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. 119e41f4b71Sopenharmony_ci 120e41f4b71Sopenharmony_ci- A maximum of 16 distributed data object instances can be created for an application. 121e41f4b71Sopenharmony_ci 122e41f4b71Sopenharmony_ci- For the sake of performance and user experience, the maximum number of devices for data collaboration is 3. 123e41f4b71Sopenharmony_ci 124e41f4b71Sopenharmony_ci- For the distributed data object of the complex type, only the root property can be modified. The subordinate properties cannot be modified. In [asset sync mechanism](#asset-sync-mechanism), the data of the asset type must support modification of its lower-level properties. 125e41f4b71Sopenharmony_ci 126e41f4b71Sopenharmony_ci- Currently, only JS APIs are supported. 127e41f4b71Sopenharmony_ci 128e41f4b71Sopenharmony_ci## Available APIs 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ciMost of the APIs for cross-device sync 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-arkdata/js-apis-data-distributedobject.md). 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci 134e41f4b71Sopenharmony_ci| API| Description| 135e41f4b71Sopenharmony_ci| -------- | -------- | 136e41f4b71Sopenharmony_ci| create(context: Context, source: object): DataObject | Creates a distributed data object instance.| 137e41f4b71Sopenharmony_ci| genSessionId(): string | Generates a session ID for distributed data objects.| 138e41f4b71Sopenharmony_ci| setSessionId(sessionId: string, callback: AsyncCallback<void>): void | Sets a session ID for data sync. Automatic sync is performed for devices with the same session ID on a trusted network.| 139e41f4b71Sopenharmony_ci| setSessionId(callback: AsyncCallback<void>): void | Exits all sessions.| 140e41f4b71Sopenharmony_ci| on(type: 'change', callback: (sessionId: string, fields: Array<string>) => void): void | Subscribes to data changes of the distributed data object.| 141e41f4b71Sopenharmony_ci| off(type: 'change', callback?: (sessionId: string, fields: Array<string>) => void): void | Unsubscribes from data changes of the distributed data object.| 142e41f4b71Sopenharmony_ci| on(type: 'status', callback: (sessionId: string, networkId: string, status: 'online' \| 'offline' ) => void): void | Subscribes to status changes of the distributed data object.| 143e41f4b71Sopenharmony_ci| off(type: 'status', callback?: (sessionId: string, networkId: string, status: 'online' \|'offline' ) => void): void | Unsubscribes from status changes of the distributed data object.| 144e41f4b71Sopenharmony_ci| save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void | Saves a distributed data object.| 145e41f4b71Sopenharmony_ci| revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void | Revokes the saving of the distributed data object.| 146e41f4b71Sopenharmony_ci| bindAssetStore(assetKey: string, bindInfo: BindInfo, callback: AsyncCallback<void>): void | Binds an asset and its RDB store.| 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ci## How to Develop 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ci### Using Distributed Data Objects in Cross-Device Migration 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ci1. Create a distributed data object in **onContinue()** for the application on the source device, and save data. 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ci 1.1 Call **create()** to create a distributed data object instance. 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci 1.2 Call **genSessionId()** to generate a **sessionId**, call **setSessionId()** to set a **sessionId**, and add the **sessionId** to **wantParam**. The distributed data objects with the same **sessionId** can connect to the same network. 158e41f4b71Sopenharmony_ci 159e41f4b71Sopenharmony_ci 1.3 Obtain the network ID from **wantParam** for the application on the target device and call **save()** with this network ID to save data to the target device. 160e41f4b71Sopenharmony_ci 161e41f4b71Sopenharmony_ci2. Create a distributed data object in **onCreate()** and **onNewWant()** for the application on the target device, and register a listener for the "restored" state. 162e41f4b71Sopenharmony_ci 163e41f4b71Sopenharmony_ci 2.1 Call **create()** to create a distributed data object instance for the application on the target device. 164e41f4b71Sopenharmony_ci 165e41f4b71Sopenharmony_ci 2.2 Register a listener callback for the data recovery state. If "restored" is returned by the listener callback registered, the distributed data object of the target device has obtained the data transferred from the source device. 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci 2.3 Obtain the **sessionId** of the source device from **want.parameters** and call **setSessionId** to set the same **sessionId** for the target device. 168e41f4b71Sopenharmony_ci 169e41f4b71Sopenharmony_ci> **NOTE** 170e41f4b71Sopenharmony_ci> 171e41f4b71Sopenharmony_ci> - In cross-device migration, after **setsessionId()** is called on the source device to set **sessionId**, call **save()** to save data to the target device. 172e41f4b71Sopenharmony_ci> 173e41f4b71Sopenharmony_ci<!--RP1--> 174e41f4b71Sopenharmony_ci> - The **continuable** tag must be set for cross-device migration. For details, see [How to Develop](../application-models/hop-cross-device-migration.md#how-to-develop).<!--RP1End--> 175e41f4b71Sopenharmony_ci> 176e41f4b71Sopenharmony_ci> - The **sessionId** field in **wantParam** is used by other services. You are advised to customize a key for accessing the **sessionId** field. 177e41f4b71Sopenharmony_ci> 178e41f4b71Sopenharmony_ci> - Use data of the Asset type to record information about assets (such as documents, images, and videos). When asset data is migrated, the corresponding asset is also migrated to the target device. 179e41f4b71Sopenharmony_ci> 180e41f4b71Sopenharmony_ci> - The initial value of the service data must be set to **undefined** on the target device so that the data saved on the source device can be restored on the target device. Otherwise, the data on the source device will be overwritten by the data set on the target device. For asset data, you need to set each attribute of the asset data to an empty string instead of setting the entire asset data to **undefined**. 181e41f4b71Sopenharmony_ci> 182e41f4b71Sopenharmony_ci> - Currently, the asset array is not supported. If multiple files need to be migrated, define an asset data record for each file to migrate. 183e41f4b71Sopenharmony_ci> 184e41f4b71Sopenharmony_ci> - Currently, only files in distributed file directory can be migrated. Files in other directories can be copied or moved to distributed file directory before migration. For details about how to move or copy files and obtain URIs, see [File Management](../reference/apis-core-file-kit/js-apis-file-fs.md) and [File URI](../reference/apis-core-file-kit/js-apis-file-fileuri.md). 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ci```ts 187e41f4b71Sopenharmony_ciimport { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 188e41f4b71Sopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'; 189e41f4b71Sopenharmony_ciimport { window } from '@kit.ArkUI'; 190e41f4b71Sopenharmony_ciimport { commonType, distributedDataObject } from '@kit.ArkData'; 191e41f4b71Sopenharmony_ciimport { fileIo, fileUri } from '@kit.CoreFileKit'; 192e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci// Define service data. 195e41f4b71Sopenharmony_ciclass Data { 196e41f4b71Sopenharmony_ci title: string | undefined; 197e41f4b71Sopenharmony_ci text: string | undefined; 198e41f4b71Sopenharmony_ci attachment: commonType.Asset; // Use data of the commonType.Asset to record files in the distributed file directory. When asset data is migrated, the corresponding files are also migrated to the target device. (If files do not need to be migrated, do not set this field and createAttachment and createEmptyAttachment.) 199e41f4b71Sopenharmony_ci // attachment2: commonType.Asset; // The asset array is not supported currently. If multiple files need to be migrated, define an asset data record for each file to migrate. 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci constructor(title: string | undefined, text: string | undefined, attachment: commonType.Asset) { 202e41f4b71Sopenharmony_ci this.title = title; 203e41f4b71Sopenharmony_ci this.text = text; 204e41f4b71Sopenharmony_ci this.attachment = attachment; 205e41f4b71Sopenharmony_ci } 206e41f4b71Sopenharmony_ci} 207e41f4b71Sopenharmony_ci 208e41f4b71Sopenharmony_ciconst TAG = '[DistributedDataObject]'; 209e41f4b71Sopenharmony_cilet dataObject: distributedDataObject.DataObject; 210e41f4b71Sopenharmony_ci 211e41f4b71Sopenharmony_ciexport default class EntryAbility extends UIAbility { 212e41f4b71Sopenharmony_ci // 1. Create a distributed data object in **onContinue()** for the application on the source device, and save data to the target device. 213e41f4b71Sopenharmony_ci onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult | Promise<AbilityConstant.OnContinueResult> { 214e41f4b71Sopenharmony_ci // 1.1 Call create() to create a distributed data object instance. 215e41f4b71Sopenharmony_ci let attachment = this.createAttachment(); 216e41f4b71Sopenharmony_ci let data = new Data('The title', 'The text', attachment); 217e41f4b71Sopenharmony_ci dataObject = distributedDataObject.create(this.context, data); 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ci // 1.2 Call genSessionId() to generate a sessionId, call setSessionId() to set a sessionId, and add the sessionId to wantParam. 220e41f4b71Sopenharmony_ci let sessionId = distributedDataObject.genSessionId(); 221e41f4b71Sopenharmony_ci console.log(TAG + `gen sessionId: ${sessionId}`); 222e41f4b71Sopenharmony_ci dataObject.setSessionId(sessionId); 223e41f4b71Sopenharmony_ci wantParam.distributedSessionId = sessionId; 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci // 1.3 Obtain networkId from **wantParam** for the application on the target device and call save() with this network ID to save data to the target device. 226e41f4b71Sopenharmony_ci let deviceId = wantParam.targetDevice as string; 227e41f4b71Sopenharmony_ci console.log(TAG + `get deviceId: ${deviceId}`); 228e41f4b71Sopenharmony_ci dataObject.save(deviceId); 229e41f4b71Sopenharmony_ci return AbilityConstant.OnContinueResult.AGREE; 230e41f4b71Sopenharmony_ci } 231e41f4b71Sopenharmony_ci 232e41f4b71Sopenharmony_ci // 2. Create a distributed data object in onCreate() for the application on the target device (for cold start), and add it to the network for data migration. 233e41f4b71Sopenharmony_ci onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 234e41f4b71Sopenharmony_ci if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 235e41f4b71Sopenharmony_ci if (want.parameters && want.parameters.distributedSessionId) { 236e41f4b71Sopenharmony_ci this.restoreDistributedDataObject(want); 237e41f4b71Sopenharmony_ci } 238e41f4b71Sopenharmony_ci } 239e41f4b71Sopenharmony_ci } 240e41f4b71Sopenharmony_ci 241e41f4b71Sopenharmony_ci // 2. Create a distributed data object in onNewWant() for the application on the target device (for hot start), and add it to the network for data migration. 242e41f4b71Sopenharmony_ci onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { 243e41f4b71Sopenharmony_ci if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) { 244e41f4b71Sopenharmony_ci if (want.parameters && want.parameters.distributedSessionId) { 245e41f4b71Sopenharmony_ci this.restoreDistributedDataObject(want); 246e41f4b71Sopenharmony_ci } 247e41f4b71Sopenharmony_ci } 248e41f4b71Sopenharmony_ci } 249e41f4b71Sopenharmony_ci 250e41f4b71Sopenharmony_ci restoreDistributedDataObject(want: Want) { 251e41f4b71Sopenharmony_ci if (!want.parameters || !want.parameters.distributedSessionId) { 252e41f4b71Sopenharmony_ci console.error(TAG + 'missing sessionId'); 253e41f4b71Sopenharmony_ci return; 254e41f4b71Sopenharmony_ci } 255e41f4b71Sopenharmony_ci 256e41f4b71Sopenharmony_ci // 2.1 Call create() to create a distributed data object instance for the application on the target device. 257e41f4b71Sopenharmony_ci let attachment = this.createEmptyAttachment(); // Set each attribute of the asset data to an empty string so that the asset data saved on the source device can be restored on the target device. 258e41f4b71Sopenharmony_ci let data = new Data(undefined, undefined, attachment); 259e41f4b71Sopenharmony_ci dataObject = distributedDataObject.create(this.context, data); 260e41f4b71Sopenharmony_ci 261e41f4b71Sopenharmony_ci // 2.2 Register a listener callback for the data recovery state. If "restored" is returned by the listener callback registered, the distributed data object of the target device has obtained the data transferred from the source device. If asset data is migrated, the file is also transferred to the target device. 262e41f4b71Sopenharmony_ci dataObject.on('status', (sessionId: string, networkId: string, status: string) => { 263e41f4b71Sopenharmony_ci if (status == 'restored') {// "restored" indicates that the data saved on the source device is restored on the target device. 264e41f4b71Sopenharmony_ci console.log(TAG + `title: ${dataObject['title']}, text: ${dataObject['text']}`); 265e41f4b71Sopenharmony_ci } 266e41f4b71Sopenharmony_ci }); 267e41f4b71Sopenharmony_ci 268e41f4b71Sopenharmony_ci // 2.3 Obtain the sessionId of the source device from want.parameters and call setSessionId to set the same sessionId for the target device. 269e41f4b71Sopenharmony_ci let sessionId = want.parameters.distributedSessionId as string; 270e41f4b71Sopenharmony_ci console.log(TAG + `get sessionId: ${sessionId}`); 271e41f4b71Sopenharmony_ci dataObject.setSessionId(sessionId); 272e41f4b71Sopenharmony_ci } 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci // Create a file in the distributed file directory and use data of the asset type to record the file information. (You can also use the data of asset type to record an existing file in the distributed file directory or copy or move a file from another directory to the distributed file directory and then migrate it.) 275e41f4b71Sopenharmony_ci createAttachment() { 276e41f4b71Sopenharmony_ci let attachment = this.createEmptyAttachment(); 277e41f4b71Sopenharmony_ci try { 278e41f4b71Sopenharmony_ci let distributedDir: string = this.context.distributedFilesDir; // Distributed file directory. 279e41f4b71Sopenharmony_ci let fileName: string = 'text_attachment.txt'; // File name. 280e41f4b71Sopenharmony_ci let filePath: string = distributedDir + '/' + fileName; // File path. 281e41f4b71Sopenharmony_ci let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); 282e41f4b71Sopenharmony_ci fileIo.writeSync(file.fd, 'The text in attachment'); 283e41f4b71Sopenharmony_ci fileIo.closeSync(file.fd); 284e41f4b71Sopenharmony_ci let uri: string = fileUri.getUriFromPath(filePath); // Obtain the file URI. 285e41f4b71Sopenharmony_ci let stat = fileIo.statSync(filePath); // Obtain detailed file attribute information. 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci // Write asset data. 288e41f4b71Sopenharmony_ci attachment = { 289e41f4b71Sopenharmony_ci name: fileName, 290e41f4b71Sopenharmony_ci uri: uri, 291e41f4b71Sopenharmony_ci path: filePath, 292e41f4b71Sopenharmony_ci createTime: stat.ctime.toString(), 293e41f4b71Sopenharmony_ci modifyTime: stat.mtime.toString(), 294e41f4b71Sopenharmony_ci size: stat.size.toString() 295e41f4b71Sopenharmony_ci } 296e41f4b71Sopenharmony_ci } catch (e) { 297e41f4b71Sopenharmony_ci let err = e as BusinessError; 298e41f4b71Sopenharmony_ci console.error(TAG + `file error, error code: ${err.code}, error message: ${err.message}`); 299e41f4b71Sopenharmony_ci } 300e41f4b71Sopenharmony_ci return attachment; 301e41f4b71Sopenharmony_ci } 302e41f4b71Sopenharmony_ci 303e41f4b71Sopenharmony_ci createEmptyAttachment() { 304e41f4b71Sopenharmony_ci let attachment: commonType.Asset = { 305e41f4b71Sopenharmony_ci name: '', 306e41f4b71Sopenharmony_ci uri: '', 307e41f4b71Sopenharmony_ci path: '', 308e41f4b71Sopenharmony_ci createTime: '', 309e41f4b71Sopenharmony_ci modifyTime: '', 310e41f4b71Sopenharmony_ci size: '' 311e41f4b71Sopenharmony_ci } 312e41f4b71Sopenharmony_ci return attachment; 313e41f4b71Sopenharmony_ci } 314e41f4b71Sopenharmony_ci} 315e41f4b71Sopenharmony_ci``` 316e41f4b71Sopenharmony_ci 317e41f4b71Sopenharmony_ci### Using Distributed Data Objects in Multi-Device Collaboration 318e41f4b71Sopenharmony_ci 319e41f4b71Sopenharmony_ci1. Call **startAbilityByCall()** to start an ability on another device. 320e41f4b71Sopenharmony_ci 321e41f4b71Sopenharmony_ci 1.1 Call **genSessionId()** to create a **sessionId** and obtain the network ID of the peer device through the distributed device management interface. 322e41f4b71Sopenharmony_ci 323e41f4b71Sopenharmony_ci 1.2 Assemble **want** and put **sessionId** into **want**. 324e41f4b71Sopenharmony_ci 325e41f4b71Sopenharmony_ci 1.3 Call **startAbilityByCall()** to start the peer ability. 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci2. Create a distributed data object on the caller device and adds it to the network. 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci 2.1 Create a distributed data object instance. 330e41f4b71Sopenharmony_ci 331e41f4b71Sopenharmony_ci 2.2 Register a listener callback for data changes. 332e41f4b71Sopenharmony_ci 333e41f4b71Sopenharmony_ci 2.3 Set a **sessionId** for the distributed data object and add it to the network. 334e41f4b71Sopenharmony_ci 335e41f4b71Sopenharmony_ci3. Create a distributed data object on the peer device and restore the data saved on the caller device. 336e41f4b71Sopenharmony_ci 337e41f4b71Sopenharmony_ci 3.1 Create a distributed data object instance on the peer device. 338e41f4b71Sopenharmony_ci 339e41f4b71Sopenharmony_ci 3.2 Register a listener callback for data changes. 340e41f4b71Sopenharmony_ci 341e41f4b71Sopenharmony_ci 3.3 Obtain **sessionId** of the caller device from **want** and add the distributed data object instance to the network with the **sessionId**. 342e41f4b71Sopenharmony_ci 343e41f4b71Sopenharmony_ci> **NOTE** 344e41f4b71Sopenharmony_ci> 345e41f4b71Sopenharmony_ci> - Currently, <!--RP3-->distributed data objects can be used only in [multi-device collaboration using the cross-device call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call) to sync data.<!--RP3End--> 346e41f4b71Sopenharmony_ci> 347e41f4b71Sopenharmony_ci> - To implement multi-device collaboration using the cross-device call, <!--RP4-->you need to apply for the ohos.permission.DISTRIBUTED_DATASYNC permission and set **launchType** to **singleton**. For details, see [How to Develop](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).<!--RP4End--> 348e41f4b71Sopenharmony_ci> 349e41f4b71Sopenharmony_ci> - The **sessionId** field in **wantParam** is used by other services. You are advised to customize a key for accessing the **sessionId** field. 350e41f4b71Sopenharmony_ci> 351e41f4b71Sopenharmony_ci> - For details about how to obtain the network ID of the peer device, see [Querying Device Information](../distributedservice/devicemanager-guidelines.md#querying-device-information). 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci The sample code is as follows: 354e41f4b71Sopenharmony_ci 355e41f4b71Sopenharmony_ci```ts 356e41f4b71Sopenharmony_ciimport { AbilityConstant, Caller, common, UIAbility, Want } from '@kit.AbilityKit'; 357e41f4b71Sopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'; 358e41f4b71Sopenharmony_ciimport { window } from '@kit.ArkUI'; 359e41f4b71Sopenharmony_ciimport { distributedDataObject } from '@kit.ArkData'; 360e41f4b71Sopenharmony_ciimport { distributedDeviceManager } from '@kit.DistributedServiceKit'; 361e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 362e41f4b71Sopenharmony_ci 363e41f4b71Sopenharmony_ci// Define service data. 364e41f4b71Sopenharmony_ciclass Data { 365e41f4b71Sopenharmony_ci title: string | undefined; 366e41f4b71Sopenharmony_ci text: string | undefined; 367e41f4b71Sopenharmony_ci 368e41f4b71Sopenharmony_ci constructor(title: string | undefined, text: string | undefined) { 369e41f4b71Sopenharmony_ci this.title = title; 370e41f4b71Sopenharmony_ci this.text = text; 371e41f4b71Sopenharmony_ci } 372e41f4b71Sopenharmony_ci} 373e41f4b71Sopenharmony_ci 374e41f4b71Sopenharmony_ciconst TAG = '[DistributedDataObject]'; 375e41f4b71Sopenharmony_ci 376e41f4b71Sopenharmony_cilet sessionId: string; 377e41f4b71Sopenharmony_cilet caller: Caller; 378e41f4b71Sopenharmony_cilet dataObject: distributedDataObject.DataObject; 379e41f4b71Sopenharmony_ci 380e41f4b71Sopenharmony_ciexport default class EntryAbility extends UIAbility { 381e41f4b71Sopenharmony_ci // 1. Call startAbilityByCall() to start an ability on another device. 382e41f4b71Sopenharmony_ci callRemote() { 383e41f4b71Sopenharmony_ci if (caller) { 384e41f4b71Sopenharmony_ci console.error(TAG + 'call remote already'); 385e41f4b71Sopenharmony_ci return; 386e41f4b71Sopenharmony_ci } 387e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 388e41f4b71Sopenharmony_ci 389e41f4b71Sopenharmony_ci // 1.1 Call genSessionId() to create a sessionId and call getRemoteDeviceId() to obtain the network ID of the peer device. 390e41f4b71Sopenharmony_ci sessionId = distributedDataObject.genSessionId(); 391e41f4b71Sopenharmony_ci console.log(TAG + `gen sessionId: ${sessionId}`); 392e41f4b71Sopenharmony_ci let deviceId = getRemoteDeviceId(); 393e41f4b71Sopenharmony_ci if (deviceId == "") { 394e41f4b71Sopenharmony_ci console.warn(TAG + 'no remote device'); 395e41f4b71Sopenharmony_ci return; 396e41f4b71Sopenharmony_ci } 397e41f4b71Sopenharmony_ci console.log(TAG + `get remote deviceId: ${deviceId}`); 398e41f4b71Sopenharmony_ci 399e41f4b71Sopenharmony_ci // 1.2 Assemble want and put sessionId into want. 400e41f4b71Sopenharmony_ci let want: Want = { 401e41f4b71Sopenharmony_ci bundleName: 'com.example.collaboration', 402e41f4b71Sopenharmony_ci abilityName: 'EntryAbility', 403e41f4b71Sopenharmony_ci deviceId: deviceId, 404e41f4b71Sopenharmony_ci parameters: { 405e41f4b71Sopenharmony_ci 'ohos.aafwk.param.callAbilityToForeground': true, // Start the ability in the foreground. This parameter is optional. 406e41f4b71Sopenharmony_ci 'distributedSessionId': sessionId 407e41f4b71Sopenharmony_ci } 408e41f4b71Sopenharmony_ci } 409e41f4b71Sopenharmony_ci try { 410e41f4b71Sopenharmony_ci // 1.3 Call startAbilityByCall() to start the peer ability. 411e41f4b71Sopenharmony_ci context.startAbilityByCall(want).then((res) => { 412e41f4b71Sopenharmony_ci if (!res) { 413e41f4b71Sopenharmony_ci console.error(TAG + 'startAbilityByCall failed'); 414e41f4b71Sopenharmony_ci } 415e41f4b71Sopenharmony_ci caller = res; 416e41f4b71Sopenharmony_ci }) 417e41f4b71Sopenharmony_ci } catch (e) { 418e41f4b71Sopenharmony_ci let err = e as BusinessError; 419e41f4b71Sopenharmony_ci console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 420e41f4b71Sopenharmony_ci } 421e41f4b71Sopenharmony_ci } 422e41f4b71Sopenharmony_ci 423e41f4b71Sopenharmony_ci // 2. Create a distributed data object after starting the peer ability. 424e41f4b71Sopenharmony_ci createDataObject() { 425e41f4b71Sopenharmony_ci if (!caller) { 426e41f4b71Sopenharmony_ci console.error(TAG + 'call remote first'); 427e41f4b71Sopenharmony_ci return; 428e41f4b71Sopenharmony_ci } 429e41f4b71Sopenharmony_ci if (dataObject) { 430e41f4b71Sopenharmony_ci console.error(TAG + 'create dataObject already'); 431e41f4b71Sopenharmony_ci return; 432e41f4b71Sopenharmony_ci } 433e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 434e41f4b71Sopenharmony_ci 435e41f4b71Sopenharmony_ci // 2.1 Create a distributed data object instance. 436e41f4b71Sopenharmony_ci let data = new Data('The title', 'The text'); 437e41f4b71Sopenharmony_ci dataObject = distributedDataObject.create(context, data); 438e41f4b71Sopenharmony_ci 439e41f4b71Sopenharmony_ci // 2.2 Register a listener callback for data changes. 440e41f4b71Sopenharmony_ci dataObject.on('change', (sessionId: string, fields: Array<string>) => { 441e41f4b71Sopenharmony_ci fields.forEach((field) => { 442e41f4b71Sopenharmony_ci console.log(TAG + `${field}: ${dataObject[field]}`); 443e41f4b71Sopenharmony_ci }); 444e41f4b71Sopenharmony_ci }); 445e41f4b71Sopenharmony_ci // 2.3 Set a sessionId for the distributed data object and add it to the network. 446e41f4b71Sopenharmony_ci dataObject.setSessionId(sessionId); 447e41f4b71Sopenharmony_ci } 448e41f4b71Sopenharmony_ci 449e41f4b71Sopenharmony_ci // 3. Create a distributed data object on the peer device and restore the data saved on the caller device. 450e41f4b71Sopenharmony_ci onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 451e41f4b71Sopenharmony_ci if (want.parameters && want.parameters.distributedSessionId) { 452e41f4b71Sopenharmony_ci // 3.1 Create a distributed data object instance on the peer device. 453e41f4b71Sopenharmony_ci let data = new Data(undefined, undefined); 454e41f4b71Sopenharmony_ci dataObject = distributedDataObject.create(this.context, data); 455e41f4b71Sopenharmony_ci 456e41f4b71Sopenharmony_ci // 3.2 Register a listener callback for data changes. 457e41f4b71Sopenharmony_ci dataObject.on('change', (sessionId: string, fields: Array<string>) => { 458e41f4b71Sopenharmony_ci fields.forEach((field) => { 459e41f4b71Sopenharmony_ci console.log(TAG + `${field}: ${dataObject[field]}`); 460e41f4b71Sopenharmony_ci }); 461e41f4b71Sopenharmony_ci }); 462e41f4b71Sopenharmony_ci // 3.3 Obtain sessionId of the caller device from **want** and add the distributed data object instance to the network with the sessionId. 463e41f4b71Sopenharmony_ci let sessionId = want.parameters.distributedSessionId as string; 464e41f4b71Sopenharmony_ci console.log(TAG + `onCreate get sessionId: ${sessionId}`); 465e41f4b71Sopenharmony_ci dataObject.setSessionId(sessionId); 466e41f4b71Sopenharmony_ci } 467e41f4b71Sopenharmony_ci } 468e41f4b71Sopenharmony_ci} 469e41f4b71Sopenharmony_ci 470e41f4b71Sopenharmony_ci// Obtain devices on the trusted network. 471e41f4b71Sopenharmony_cifunction getRemoteDeviceId() { 472e41f4b71Sopenharmony_ci let deviceId = ""; 473e41f4b71Sopenharmony_ci try { 474e41f4b71Sopenharmony_ci let deviceManager = distributedDeviceManager.createDeviceManager('com.example.collaboration'); 475e41f4b71Sopenharmony_ci let devices = deviceManager.getAvailableDeviceListSync(); 476e41f4b71Sopenharmony_ci if (devices[0] && devices[0].networkId) { 477e41f4b71Sopenharmony_ci deviceId = devices[0].networkId; 478e41f4b71Sopenharmony_ci } 479e41f4b71Sopenharmony_ci } catch (e) { 480e41f4b71Sopenharmony_ci let err = e as BusinessError; 481e41f4b71Sopenharmony_ci console.error(TAG + `get remote deviceId error, error code: ${err.code}, error message: ${err.message}`); 482e41f4b71Sopenharmony_ci } 483e41f4b71Sopenharmony_ci return deviceId; 484e41f4b71Sopenharmony_ci} 485e41f4b71Sopenharmony_ci```