About This Codelab

Distributed Data Service (DDS) provides the capability to store data in the databases of different devices. By calling the APIs of this service, applications save data to distributed databases. Based on a triplet of the account, application, and database, DDS isolates data of different applications so that the data cannot be accessed across applications through DDS. DDS synchronizes application data between trusted devices to provide users with consistent data access experience on different devices.
For details about the DDS, see Distributed Data Service Overview.
This codelab covers the following content and provides complete sample code:

  1. Creating a distributed database
  2. Inserting data and querying data in a distributed database and deleting a distributed database
  3. Synchronizing data between distributed databases

The procedure is as follows:

To implement a distributed database, you need to apply for the ohos.permission.DISTRIBUTED_DATASYNC permission in entry\src\main\config.json to enable data exchange between devices. The sample code is as follows:

module": { ...... "reqPermissions": [ { "name": "ohos.permission.DISTRIBUTED_DATASYNC" } ] }

To create a distributed database, you need to create a KvManager instance first. The sample code is as follows:

private KvManager createManager() { KvManager manager = null; try { KvManagerConfig config = new KvManagerConfig(this); manager = KvManagerFactory.getInstance().createKvManager(config); } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "some exception happen"); } return manager; }

Use the KvManager instance to create a distributed database of the SINGLE_VERSION type, that is, a single KV store. The sample code is as follows:

private SingleKvStore createDb(KvManager kvManager) { SingleKvStore kvStore = null; try { Options options = new Options(); options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION); kvStore = kvManager.getKvStore(options, STORE_ID); } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "some exception happen"); } return kvStore; }

Subscribe to data changes of the single KV store. The sample code is as follows:

private void subscribeDb(SingleKvStore singleKvStore) { KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient(); singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_REMOTE, kvStoreObserverClient); }

Inserting Data

Construct a key and its value, and then call the putString() method to write the key and value into the distributed database.

private void writeData(String key, String value) { if (key == null || key.isEmpty() || value == null || value.isEmpty()) { return; } singleKvStore.putString(key, value); }

Querying Data

You can specify a key and query the value matching the key in the distributed database. You can also query all key-value pairs if you do not specify a key.

private void queryContact() { List<Entry> entryList = singleKvStore.getEntries(""); contactArray.clear(); try { for (Entry entry : entryList) { contactArray.add(new Contacter(entry.getValue().getString(), entry.getKey())); } } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG,"the value must be String"); } contactAdapter.notifyDataChanged(); }

Deleting a Database

Call the deleteKvStore() method with a pre-defined STORE_ID to delete a distributed database. For details about the STORE_ID, see the complete code.

@Override protected void onStop() { super.onStop(); kvManager.closeKvStore(singleKvStore); kvManager.deleteKvStore(STORE_ID); }

Before synchronizing data, obtain the device list in the current network and specify the synchronization mode (PULL_ONLY, PUSH_ONLY, or PUSH_PULL). The sample code is as follows (PUSH_PULL is used as an example):

private void syncContact() { List<DeviceInfo> deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER); List<String> deviceIdList = new ArrayList<>(); for (DeviceInfo deviceInfo : deviceInfoList) { deviceIdList.add(deviceInfo.getId()); } HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "device size= " + deviceIdList.size()); if (deviceIdList.size() == 0) { showTip("Networking failed."); return; } singleKvStore.registerSyncCallback(new SyncCallback() { @Override public void syncCompleted(Map<String, Integer> map) { getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { queryContact(); showTip("Synchronized successfully."); } }); singleKvStore.unRegisterSyncCallback(); } }); singleKvStore.sync(deviceIdList, SyncMode.PUSH_PULL); }

Add information.

Synchronize data between two devices.

Phone A

Phone B


For details about the complete code, see 9 Sample Code.

You have completed this codelab and learned the basic operations for the distributed database, including creating and deleting a database, inserting and querying data in a database, and synchronizing data between databases.

Code Structure

For your convenience, we provide the complete code for a sample distributed database project of an information management system. The code structure is as follows:

In addition to the preceding files, the project also uses three XML layout files, which are declared in the main\resources\base\layout directory.

Writing the Layout and Style

On HUAWEI DevEco Studio, create a project with Phone and Empty Feature Ability (Java) as the device type and template, respectively. Add three layout files in resources/layout.

  1. ability_contact.xml: This layout file defines the Synchronize and Add buttons and the Name, Phone number, and Information management text components. The sample code is as follows:
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:orientation="vertical"> <DependentLayout ohos:width="match_parent" ohos:height="60vp" > <Text ohos:height="match_content" ohos:width="match_content" ohos:text="Information management" ohos:text_color="#222222" ohos:text_size="22fp" ohos:center_in_parent="true" /> <Button ohos:id="$+id:addContact" ohos:height="match_content" ohos:width="match_content" ohos:text="Add" ohos:text_color="#a0a0a0" ohos:text_size="18fp" ohos:align_parent_right="true" ohos:vertical_center="true" ohos:right_margin="16vp" /> <Button ohos:id="$+id:sync" ohos:height="match_content" ohos:width="match_content" ohos:text="Synchronize" ohos:text_color="#a0a0a0" ohos:text_size="18fp" ohos:align_parent_left="true" ohos:vertical_center="true" ohos:left_margin="16vp" /> </DependentLayout> <Component ohos:height="1vp" ohos:width="match_parent" ohos:background_element="#eeeeee" /> <DirectionalLayout ohos:width="match_parent" ohos:height="40vp" ohos:orientation="horizontal" > <Text ohos:width="match_parent" ohos:height="match_content" ohos:id="$+id:name" ohos:text="Name" ohos:text_color="#222222" ohos:text_size="16fp" ohos:weight="10" ohos:text_alignment="center" ohos:layout_alignment="center" /> <Text ohos:width="match_parent" ohos:height="match_content" ohos:id="$+id:phone" ohos:text="Phone number" ohos:text_color="#555555" ohos:text_size="16fp" ohos:weight="10" ohos:text_alignment="center" ohos:layout_alignment="center" /> <Text ohos:width="match_parent" ohos:height="40vp" ohos:weight="7" ohos:left_margin="20vp" > </Text> </DirectionalLayout> <ListContainer ohos:id="$+id:listContainer" ohos:width="match_parent" ohos:height="match_parent" ohos:orientation="vertical" /> </DirectionalLayout>
  2. item_contact.xml: This layout file defines the Edit and Delete buttons following a piece of added information.
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:width="match_parent" ohos:height="41vp" ohos:orientation="vertical" > <DirectionalLayout ohos:id="$+id:dir_id" ohos:width="match_parent" ohos:height="40vp" ohos:orientation="horizontal" > <Text ohos:width="match_parent" ohos:height="match_content" ohos:id="$+id:name" ohos:text_color="#222222" ohos:text_size="16fp" ohos:weight="10" ohos:text_alignment="center" ohos:layout_alignment="center" /> <Text ohos:width="match_parent" ohos:height="match_content" ohos:id="$+id:phone" ohos:text_color="#555555" ohos:text_size="16fp" ohos:weight="10" ohos:text_alignment="center" ohos:layout_alignment="center" /> <DirectionalLayout ohos:width="match_parent" ohos:height="40vp" ohos:orientation="horizontal" ohos:left_margin="20vp" ohos:weight="7" > <Button ohos:id="$+id:edit" ohos:width="match_content" ohos:height="match_content" ohos:text="Edit" ohos:text_color="#00dddd" ohos:text_size="16fp" ohos:padding="4vp" ohos:layout_alignment="center" /> <Button ohos:id="$+id:delete" ohos:width="match_content" ohos:height="match_content" ohos:text="Delete" ohos:text_color="#cc0000" ohos:text_size="16fp" ohos:padding="4vp" ohos:layout_alignment="center" /> </DirectionalLayout> </DirectionalLayout> <Text ohos:width="match_parent" ohos:height="1vp" ohos:background_element="#aaeeeeee" ohos:left_margin="20vp" ohos:right_margin="20vp" /> </DirectionalLayout>
  3. item_dialog.xml: This layout file defines the dialog box that is displayed when the Add button is clicked. The dialog box contains the Name and Phone number text fields and the OK button.
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:width="match_parent" ohos:height="match_content" ohos:orientation="vertical" > <Text ohos:id="$+id:title" ohos:width="match_content" ohos:height="match_content" ohos:text="Add information" ohos:text_color="#111111" ohos:text_size="18fp" ohos:layout_alignment="center" ohos:top_margin="30vp" ohos:bottom_margin="30vp" /> <DirectionalLayout ohos:width="match_parent" ohos:height="40vp" ohos:orientation="horizontal" ohos:left_margin="19vp" ohos:right_margin="19vp" > <Text ohos:width="match_parent" ohos:height="match_content" ohos:text="Name:" ohos:text_color="#222222" ohos:text_size="16fp" ohos:weight="1" ohos:layout_alignment="vertical_center|left" /> <TextField ohos:width="match_parent" ohos:height="match_parent" ohos:id="$+id:name" ohos:text_color="#555555" ohos:text_size="16fp" ohos:weight="3" ohos:hint="Enter name" ohos:background_element="$graphic:background_input" ohos:text_alignment="vertical_center|left" ohos:left_padding="10vp" ohos:layout_alignment="center" /> </DirectionalLayout> <DirectionalLayout ohos:width="match_parent" ohos:height="40vp" ohos:orientation="horizontal" ohos:left_margin="19vp" ohos:right_margin="19vp" ohos:top_margin="16vp" > <Text ohos:width="match_parent" ohos:height="match_content" ohos:text="Phone number:" ohos:text_color="#222222" ohos:text_size="16fp" ohos:weight="1" ohos:layout_alignment="vertical_center|left" /> <TextField ohos:width="match_parent" ohos:height="match_parent" ohos:id="$+id:phone" ohos:text_color="#555555" ohos:text_size="16fp" ohos:weight="3" ohos:hint="Enter phone number" ohos:background_element="$graphic:background_input" ohos:text_alignment="vertical_center|left" ohos:left_padding="10vp" ohos:layout_alignment="center" /> </DirectionalLayout> <Button ohos:id="$+id:confirm" ohos:width="match_parent" ohos:height="match_content" ohos:text="OK" ohos:text_color="#ffffff" ohos:text_size="16fp" ohos:layout_alignment="center" ohos:left_margin="30vp" ohos:right_margin="30vp" ohos:top_margin="40vp" ohos:bottom_margin="40vp" ohos:bottom_padding="10vp" ohos:top_padding="10vp" ohos:background_element="$graphic:background_button" /> </DirectionalLayout>

Add the following files in the resources/base/graphic/ directory:

  1. The background_input.xml file defines the Input background attributes. The sample code is as follows:
    <?xml version="1.0" encoding="UTF-8" ?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="8vp"/> <solid ohos:color="#00000000"/> <stroke ohos:width="1vp" ohos:color="#eeeeee"/> </shape>
  2. The background_button.xml file defines the Button background attributes. The sample code is as follows
    <?xml version="1.0" encoding="UTF-8" ?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="8vp"/> <solid ohos:color="#00dddd"/> </shape>

Writing the Service Logic

  1. Add the ContactProvider.Java file in the entry\src\main\java\com\huawei\codelab\provider directory. This class improves the efficiency of using and editing data. The sample code is as follows:
    import com.huawei.cookbooks.ResourceTable; import com.huawei.cookbooks.been.Contacter; import ohos.agp.components.BaseItemProvider; import ohos.agp.components.Button; import ohos.agp.components.Component; import ohos.agp.components.ComponentContainer; import ohos.agp.components.LayoutScatter; import ohos.agp.components.Text; import ohos.app.Context; import java.util.List; /** * Contact List Adapter */ public class ContactProvider extends BaseItemProvider { private List contactArray; private Context context; private AdapterClickListener adapterClickListener; public ContactProvider(Context context, List contactArray) { this.context = context; this.contactArray = contactArray; } @Override public int getCount() { return contactArray == null ? 0 : contactArray.size(); } @Override public Object getItem(int position) { if (position < contactArray.size() && position >= 0) { return contactArray.get(position); } return null; } @Override public long getItemId(int position) { return position; } /** * Obtains the component of each item. * * @param position Indicates the index. * @param componentPara Indicates the reused component. * @param componentContainer Indicates the container. * @return Returns the component of each item. */ @Override public Component getComponent(int position, Component componentPara, ComponentContainer componentContainer) { ViewHolder viewHolder = null; Component component = componentPara; if (component == null) { component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_contact, null, false); viewHolder = new ViewHolder(); Component componentText = component.findComponentById(ResourceTable.Id_name); if (componentText instanceof Text) { viewHolder.name = (Text) componentText; } componentText = component.findComponentById(ResourceTable.Id_phone); if (componentText instanceof Text) { viewHolder.phone = (Text) componentText; } viewHolder.delete = (Button) component.findComponentById(ResourceTable.Id_delete); viewHolder.edit = (Button) component.findComponentById(ResourceTable.Id_edit); component.setTag(viewHolder); } else { if (component.getTag() instanceof ViewHolder) { viewHolder = (ViewHolder) component.getTag(); } } if (viewHolder != null) { viewHolder.name.setText(contactArray.get(position).getName()); viewHolder.phone.setText(contactArray.get(position).getPhone()); viewHolder.edit.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (adapterClickListener != null) { adapterClickListener.edit(position); } } }); viewHolder.delete.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (adapterClickListener != null) { adapterClickListener.delete(position); } } }); } return component; } private static class ViewHolder { private Text name; private Text phone; private Button edit; private Button delete; } /** * Defines the callback event interface. */ public interface AdapterClickListener { void edit(int position); void delete(int position); } public void setAdapterClickListener(AdapterClickListener adapterClickListener) { this.adapterClickListener = adapterClickListener; } }
  2. Add the Contacter.Java file in the entry\src\main\java\com\huawei\codelab\been directory.This class encapsulates the name and phone number. The sample code is as follows:
    public class Contacter { private String name; private String phone; public Contacter(String name, String phone) { this.name = name; this.phone = phone; } public String getName() { return name; } public String getPhone() { return phone; } }
  3. Add the ContactComponent.Java file in the entry\src\main\java\com\huawei\codelab\component directory. This class integrates the components used by the dialog box for adding information and initializes some information. The sample code is as follows:
    import com.huawei.cookbooks.ResourceTable; import ohos.agp.components.Component; import ohos.agp.components.DirectionalLayout; import ohos.agp.components.LayoutScatter; import ohos.agp.components.Text; import ohos.agp.components.TextField; import ohos.app.Context; /** * add/edit contact layout */ public class ContactComponent extends DirectionalLayout { private Component component; private TextField nameTextField; private TextField phoneTextField; private Text title; private DialogCallBack dialogCallBack; public ContactComponent(Context context) { super(context); addComponent(context); initView(); initEvent(); } private void initEvent() { component.findComponentById(ResourceTable.Id_confirm).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { confirmContact(); } }); } private void confirmContact() { String nameInput = nameTextField.getText(); String phoneInput = phoneTextField.getText(); if (dialogCallBack != null) { dialogCallBack.result(nameInput, phoneInput); } } private void initView() { Component componentText = component.findComponentById(ResourceTable.Id_name); if (componentText instanceof TextField) { nameTextField = (TextField) componentText; } componentText = component.findComponentById(ResourceTable.Id_phone); if (componentText instanceof TextField) { phoneTextField = (TextField) componentText; } componentText = component.findComponentById(ResourceTable.Id_title); if (componentText instanceof Text) { title = (Text) componentText; } } private void addComponent(Context context) { component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_dialog, null, false); addComponent(component); LayoutConfig layoutConfig = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_CONTENT); setLayoutConfig(layoutConfig); } public void initData(String name, String phone) { nameTextField.setBubbleSize(0,0); phoneTextField.setBubbleSize(0,0); if (name != null) { nameTextField.setText(name); } if (phone != null) { phoneTextField.setText(phone); phoneTextField.setEnabled(false); title.setText("Modify information"); } } public void setDialogCallBack(DialogCallBack dialogCallBack) { this.dialogCallBack = dialogCallBack; } public interface DialogCallBack { void result(String name, String phone); } }
  4. Add the ContactSlice.Java file in the entry\src\main\java\com\huawei\codelab\slice directory. This class implements functions such as creating and deleting a database and synchronizing data, as well as some service logic. The sample code is as follows:<
    import com.huawei.cookbooks.ResourceTable; import com.huawei.cookbooks.been.Contacter; import com.huawei.cookbooks.component.ContactComponent; import com.huawei.cookbooks.provider.ContactProvider; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.Component; import ohos.agp.components.ListContainer; import ohos.agp.utils.LayoutAlignment; import ohos.agp.window.dialog.CommonDialog; import ohos.agp.window.dialog.IDialog; import ohos.agp.window.dialog.ToastDialog; import ohos.data.distributed.common.*; import ohos.data.distributed.device.DeviceFilterStrategy; import ohos.data.distributed.device.DeviceInfo; import ohos.data.distributed.user.SingleKvStore; import ohos.hiviewdfx.HiLog; import ohos.hiviewdfx.HiLogLabel; import java.util.ArrayList; import java.util.List; import java.util.Map; public class ContactSlice extends AbilitySlice implements ContactProvider.AdapterClickListener { private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "HiContact"); private static final String LOG_FORMAT = "%{public}s: %{public}s"; private static final String TAG = "ContactSlice"; private static final String STORE_ID = "contact_db1"; private static final int DIALOG_SIZE_WIDTH = 800; private static final int DIALOG_SIZE_HEIGHT = 800; private static final int SHOW_TIME = 1500; private ContactProvider contactAdapter; private List contactArray; private KvManager kvManager; private SingleKvStore singleKvStore; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_contact); initDbManager(); initList(); initEvent(); queryContact(); } /** * Initialize click event */ private void initEvent() { findComponentById(ResourceTable.Id_addContact).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { addContact(); } }); findComponentById(ResourceTable.Id_sync).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { syncContact(); } }); } /** * Initialize ListContainer */ private void initList() { Component component = findComponentById(ResourceTable.Id_listContainer); ListContainer listContainer; if (component instanceof ListContainer) { listContainer = (ListContainer) component; contactArray = new ArrayList<>(); contactAdapter = new ContactProvider(this, contactArray); listContainer.setItemProvider(contactAdapter); contactAdapter.setAdapterClickListener(this); } } /** * Synchronizing contacts data */ private void syncContact() { List deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER); List deviceIdList = new ArrayList<>(); for (DeviceInfo deviceInfo : deviceInfoList) { deviceIdList.add(deviceInfo.getId()); } HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "device size= " + deviceIdList.size()); if (deviceIdList.size() == 0) { showTip("Networking failed."); return; } singleKvStore.registerSyncCallback(new SyncCallback() { @Override public void syncCompleted(Map map) { getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "sync success"); queryContact(); showTip("Synchronized successfully."); } }); singleKvStore.unRegisterSyncCallback(); } }); singleKvStore.sync(deviceIdList, SyncMode.PUSH_PULL); } /** * Initializing Database Management */ private void initDbManager() { kvManager = createManager(); singleKvStore = createDb(kvManager); subscribeDb(singleKvStore); } /** * Creates a distributed database manager. * * @return Returns the distributed database manager. */ private KvManager createManager() { KvManager manager = null; try { KvManagerConfig config = new KvManagerConfig(this); manager = KvManagerFactory.getInstance().createKvManager(config); } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "some exception happen"); } return manager; } /** * Creates a SingleKvStore object using a specified kvManager. * * @param kvManager Indicates the kvManager. * @return Returns the SingleKvStore object. */ private SingleKvStore createDb(KvManager kvManager) { SingleKvStore kvStore = null; try { Options options = new Options(); options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION); kvStore = kvManager.getKvStore(options, STORE_ID); } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "some exception happen"); } return kvStore; } /** * Subscribing to All (Currently, Remote) Data Change Notifications of a Single-Version Distributed Database * * @param singleKvStore Data operation */ private void subscribeDb(SingleKvStore singleKvStore) { KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient(); singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_REMOTE, kvStoreObserverClient); } /** * Receive database messages */ private class KvStoreObserverClient implements KvStoreObserver { @Override public void onChange(ChangeNotification notification) { getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "come to auto sync"); queryContact(); showTip("Synchronized successfully."); } }); } } /** * Query Local Contacts */ private void queryContact() { List entryList = singleKvStore.getEntries(""); HiLog.info(LABEL_LOG, LOG_FORMAT,TAG,"entryList size" + entryList.size()); contactArray.clear(); try { for (Entry entry : entryList) { contactArray.add(new Contacter(entry.getValue().getString(), entry.getKey())); } } catch (KvStoreException exception) { HiLog.info(LABEL_LOG, LOG_FORMAT,TAG,"the value must be String"); } contactAdapter.notifyDataChanged(); } /** * Write key-value data to the single-version distributed database. * * @param key Stored key * @param value Stored value */ private void writeData(String key, String value) { if (key == null || key.isEmpty() || value == null || value.isEmpty()) { return; } singleKvStore.putString(key, value); HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "writeContact key= " + key + " writeContact value= " + value); } /** * Deleting Key Value Data from the Single-Version Distributed Database * * @param key Deleted Key */ private void deleteData(String key) { if (key.isEmpty()) { return; } singleKvStore.delete(key); HiLog.info(LABEL_LOG, LOG_FORMAT,TAG, "deleteContact key= " + key); } /** * Add Contact */ private void addContact() { showDialog(null, null, new ContactComponent.DialogCallBack() { @Override public void result(String name, String phone) { writeData(phone, name); contactArray.add(new Contacter(name, phone)); contactAdapter.notifyDataSetItemInserted(contactAdapter.getCount()); queryContact(); } }); } /** * Display dialog box * * @param name Contacts * @param phone phone * @param dialogCallBack callback result */ private void showDialog(String name, String phone, ContactComponent.DialogCallBack dialogCallBack) { CommonDialog commonDialog = new CommonDialog(this); ContactComponent component = new ContactComponent(this); component.initData(name, phone); component.setDialogCallBack(new ContactComponent.DialogCallBack() { @Override public void result(String nameInput, String phoneInput) { if (nameInput.isEmpty() || phoneInput.isEmpty()) { showTip("Name and phone number are mandatory."); return; } if (phone == null && phoneIsExist(phoneInput)) { showTip("Phone number already exists."); return; } if (dialogCallBack != null) { dialogCallBack.result(nameInput, phoneInput); } commonDialog.remove(); } }); commonDialog.setAutoClosable(true); commonDialog.setContentCustomComponent(component); commonDialog.show(); } /** * Checks whether the mobile phone number exists. * * @param phone Indicates the mobile phone number to check. * @return Returns a boolean value indicating whether the mobile phone number exists. */ private boolean phoneIsExist(String phone) { List entryList = singleKvStore.getEntries(""); for (Entry entry : entryList) { if (entry.getKey().equals(phone)) { return true; } } return false; } /** * Event triggered by clicking each edit button * * @param position Position of the item number */ @Override public void edit(int position) { Contacter contacter = contactArray.get(position); showDialog(contacter.getName(), contacter.getPhone(), new ContactComponent.DialogCallBack() { @Override public void result(String name, String phone) { writeData(phone, name); contactArray.set(position, new Contacter(name, phone)); contactAdapter.notifyDataSetItemChanged(position); queryContact(); } }); } /** * Event triggered by clicking each delete button * * @param position Position of the item number */ @Override public void delete(int position) { CommonDialog commonDialog = new CommonDialog(this); commonDialog.setSize(DIALOG_SIZE_WIDTH, DIALOG_SIZE_HEIGHT); commonDialog.setAutoClosable(true); commonDialog.setTitleText(" Warning") .setContentText(" Delete the information?") .setButton(0, "Cancel", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int i) { iDialog.destroy(); } }) .setButton(1, "OK", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int i) { if (position > contactArray.size() - 1) { showTip("The information to delete does not exist."); return; } deleteData(contactArray.get(position).getPhone()); contactArray.remove(position); contactAdapter.notifyDataChanged(); showTip("Deleted successfully."); iDialog.destroy(); } }).show(); } /** * tip message * * @param message message */ private void showTip(String message) { new ToastDialog(this).setAlignment(LayoutAlignment.CENTER) .setText(message).setDuration(SHOW_TIME).show(); } @Override protected void onStop() { super.onStop(); kvManager.closeKvStore(singleKvStore); kvManager.deleteKvStore(STORE_ID); } }
  5. Add the page route and the method for dynamically requesting permissions in the MainAbility.Java file. The sample code is as follows:
    import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; import ohos.bundle.IBundleManager; import com.huawei.codelab.slice.ContactSlice; public class MainAbility extends Ability { private static final String DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; private static final int PERMISSION_CODE = 20201203; @Override public void onStart(Intent intent) { super.onStart(intent); super.setMainRoute(ContactSlice.class.getName()); requestPermission(); } private void requestPermission() { if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) { if (canRequestPermission(DISTRIBUTED_DATASYNC)) { requestPermissionsFromUser( new String[]{DISTRIBUTED_DATASYNC}, PERMISSION_CODE); } } } }
Code copied