
如何使用分布式数据库方法详解
1. 如何使用分布式数据库
介绍
分布式数据服务(Distributed Data Service,DDS) 为应用程序提供不同设备间数据库数据分布式的能力。通过调用分布式数据接口,应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组,分布式数据服务对属于不同的应用的数据进行隔离,保证不同应用之间的数据不能通过分布式数据服务互相访问。在通过可信认证的设备间,分布式数据服务支持应用数据相互同步,为用户提供在多种终端设备上一致的数据访问体验。
有关分布式数据服务更加详细的介绍可以参考分布式数据服务。
本教程将为您完整介绍以下内容并展示完整示例:
- 分布式数据库的创建
- 分布式数据库的插入和删除
- 分布式数据库的数据同步
说明:
实现分布式数据库,需要至少两个设备处于同一个分布式网络中,可以通过操作如下配置实现:所有设备接入同一网络,
所有设备登陆相同华为账号,
所有设备上开启“设置->更多连接->多设备协同 ”
2. 实现分布式数据库需要申请的权限
为了实现分布式数据库,需要在entry\src\main\config.json中申请ohos.permission.DISTRIBUTED_DATASYNC权限,以便允许不同设备间的数据交换。示例代码如下:
module": {
......
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
3. 如何创建分布式数据库
要创建分布式数据库,首先要做的就是创建分布式数据库管理器实例KvManager,我们定义了如下方法:
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;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
创建成功后,借助KvManager创建SINGLE_VERSION分布式数据库,方法如下:
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;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
说明:
SINGLE_VERSION分布式数据库是指数据在本地保存是以单个KV条目为单位的方式保存,对每个Key最多只保存一个条目项,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。
最后是订阅分布式数据库中数据变化,方法如下:
private void subscribeDb(SingleKvStore singleKvStore) {
KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient();
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_REMOTE, kvStoreObserverClient);
}
- 1.
- 2.
- 3.
- 4.
4. 如何进行数据查询、插入和删除
数据插入
在将数据写入分布式数据库之前,需要先构造分布式数据库的Key(键)和Value(值),通过putString方法将数据写入到数据库中,具体示例如下:
private void writeData(String key, String value) {
if (key == null || key.isEmpty() || value == null || value.isEmpty()) {
return;
}
singleKvStore.putString(key, value);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
数据查询
分布式数据库中的数据查询是根据Key(键)来进行的,如果指定Key(键),则会查询出对应Key(键)的数据;如果不指定Key,既为空,则查询出所有数据,查询示例代码如下
private void queryContact() {
List 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();
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
说明:
以上代码除查询外,还有部分场景业务代码。
数据删除
对于分布式数据库的删除操作,可以直接调用deleteKvStore()方法,但是需要传递事先定义好的STORE_ID参数(具体定义参考下文完整代码),示例代码如下:
@Override
protected void onStop() {
super.onStop();
kvManager.closeKvStore(singleKvStore);
kvManager.deleteKvStore(STORE_ID);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
5. 如何进行分布式数据库的同步
在进行数据同步之前,首先需要先获取当前组网环境中的设备列表,然后指定同步方式(PULL_ONLY,PUSH_ONLY,PUSH_PULL)进行同步,以PUSH_PULL方式为例,示例代码如下:
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("组网失败");
return;
}
singleKvStore.registerSyncCallback(new SyncCallback() {
@Override
public void syncCompleted(Map<String, Integer> map) {
getUITaskDispatcher().asyncDispatch(new Runnable() {
@Override
public void run() {
queryContact();
showTip("同步成功");
}
});
singleKvStore.unRegisterSyncCallback();
}
});
singleKvStore.sync(deviceIdList, SyncMode.PUSH_PULL);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
说明:
以上代码除数据同步外,还有部分场景业务代码。
6. 最终实现效果

8. 示例代码
代码结构解读
为了方便您的学习,我们提供了的分布式数据库示例工程的完整代码,工程以一个简易的信息管理系统为背景,代码的工程结构如下:
- Provider:ContactProvider为数据信息的适配器,主要作用为高效传递和使用相关数据。
- Been:Contacter封装了联系人信息。
- Componet:ContactComponent添加和修改信息的Dialog实现类。
- Slice:ContactSlice应用主页面,分布式数据库逻辑实现类。
除以上文件,工程中还用到了三个xml布局文件,他们声明在了main\resources\base\layout目录下。
编写布局和样式
首先在HUAWEI DevEco Studio创建一个Phone的Empty Feature Ability(Java)模板工程,然后在 "resources/layout"下新增三个布局。
ability_contact.xml:该布局定义了"同步"和"添加"两个Button,姓名、手机号码、信息管理三个Text,具体代码如下:
<?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="信息管理"
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="添加"
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="同步"
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="姓名"
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="手机号码"
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>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
item_contact.xml:该布局为新增信息后,每条信息后面的编辑和删除Button,具体代码如下:
<?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="编辑"
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="删除"
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>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
item_dialog.xml:该布局为点击添加按钮后出现的Dialog,主要由姓名和手机号码TextFIeld,以及确认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="添加信息"
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="姓名:"
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="输入姓名"
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="手机号码:"
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="输入手机号"
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="确认"
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>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
随后在“resources/base/graphic/”目录下增加如下文件:
background_input.xml文件用来定义Input背景属性,示例代码如下:
<?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>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
background_button.xml文件用来定义Button背景属性,示例代码如下:
<?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>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
业务逻辑代码
在"entry\src\main\java\com\huawei\codelab\provider"下新增ContactProvider.Java文件,该类的主要作用是提高使用和编辑数据的效率,示例代码如下:
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;
}
/**
* Component of each item
*
* @param position Index
* @param componentPara Reused Component
* @param componentContainer Container
* @return 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;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
在"entry\src\main\java\com\huawei\codelab\been"下新增Contacter.Java文件,该类的主要作用是封装姓名和电话号信息,示例代码如下:
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;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
在"entry\src\main\java\com\huawei\codelab\componet"下新增ContactComponent.Java文件,该类的主要作用是整合添加数据时dialog用到的组件以及初始化部分数据,示例代码如下:
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("修改信息");
}
}
public void setDialogCallBack(DialogCallBack dialogCallBack) {
this.dialogCallBack = dialogCallBack;
}
public interface DialogCallBack {
void result(String name, String phone);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
在"entry\src\main\java\com\huawei\codelab\slice"下新增ContactSlice.Java文件,该类主要实现了分布式数据的创建,删除,和同步等操作以及部分业务逻辑,具体示例代码如下:
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("组网失败");
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("同步成功");
}
});
singleKvStore.unRegisterSyncCallback();
}
});
singleKvStore.sync(deviceIdList, SyncMode.PUSH_PULL);
}
/**
* Initializing Database Management
*/
private void initDbManager() {
kvManager = createManager();
singleKvStore = createDb(kvManager);
subscribeDb(singleKvStore);
}
/**
* Create a distributed database manager instance
*
* @return 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;
}
/**
* Creating a Single-Version Distributed Database
*
* @param kvManager Database management
* @return SingleKvStore
*/
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("同步成功");
}
});
}
}
/**
* 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("姓名与手机号码必填");
return;
}
if (phone == null && phoneIsExist(phoneInput)) {
showTip("手机号码已经存在了");
return;
}
if (dialogCallBack != null) {
dialogCallBack.result(nameInput, phoneInput);
}
commonDialog.remove();
}
});
commonDialog.setAutoClosable(true);
commonDialog.setContentCustomComponent(component);
commonDialog.show();
}
/**
* Check whether the mobile number exists
*
* @param phone phone
* @return boolean
*/
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(" 警告")
.setContentText(" 确定要删除吗?")
.setButton(0, "取消", new IDialog.ClickedListener() {
@Override
public void onClick(IDialog iDialog, int i) {
iDialog.destroy();
}
})
.setButton(1, "确认", new IDialog.ClickedListener() {
@Override
public void onClick(IDialog iDialog, int i) {
if (position > contactArray.size() - 1) {
showTip("要删除的元素不存在");
return;
}
deleteData(contactArray.get(position).getPhone());
contactArray.remove(position);
contactAdapter.notifyDataChanged();
showTip("删除成功");
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);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
最后在MainAbility.Java文件中增加页面路由和动态权限申请,具体示例代码如下:
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);
}
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
恭喜您
通过本教程的学习,您已经学会了分布式数据库服务的基础操作(创建、新增、删除、同步)。
微信扫码分享
