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![distributedObject](figures/distributedObject.jpg)
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![distributedObject_sync](figures/distributedObject_sync.jpg)
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![distributedObject_syncView](figures/distributedObject_syncView.jpg)
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&lt;void&gt;): 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&lt;void&gt;): void | Exits all sessions.|
140e41f4b71Sopenharmony_ci| on(type: 'change', callback: (sessionId: string, fields: Array&lt;string&gt;) => void): void | Subscribes to data changes of the distributed data object.|
141e41f4b71Sopenharmony_ci| off(type: 'change', callback?: (sessionId: string, fields: Array&lt;string&gt;) => 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&lt;SaveSuccessResponse&gt;): void | Saves a distributed data object.|
145e41f4b71Sopenharmony_ci| revokeSave(callback: AsyncCallback&lt;RevokeSaveSuccessResponse&gt;): void | Revokes the saving of the distributed data object.|
146e41f4b71Sopenharmony_ci| bindAssetStore(assetKey: string, bindInfo: BindInfo, callback: AsyncCallback&lt;void&gt;): 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```