如何使用分布式数据库方法详解

奶盖
发布于 2021-7-20 10:54
浏览
2收藏

1. 如何使用分布式数据库

 

介绍

 

分布式数据服务(Distributed Data Service,DDS) 为应用程序提供不同设备间数据库数据分布式的能力。通过调用分布式数据接口,应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组,分布式数据服务对属于不同的应用的数据进行隔离,保证不同应用之间的数据不能通过分布式数据服务互相访问。在通过可信认证的设备间,分布式数据服务支持应用数据相互同步,为用户提供在多种终端设备上一致的数据访问体验。
有关分布式数据服务更加详细的介绍可以参考分布式数据服务
本教程将为您完整介绍以下内容并展示完整示例:

  1. 分布式数据库的创建
  2. 分布式数据库的插入和删除
  3. 分布式数据库的数据同步

 

 说明:
实现分布式数据库,需要至少两个设备处于同一个分布式网络中,可以通过操作如下配置实现:

所有设备接入同一网络,
所有设备登陆相同华为账号,
所有设备上开启“设置->更多连接->多设备协同 ”

 

2. 实现分布式数据库需要申请的权限

 

为了实现分布式数据库,需要在entry\src\main\config.json中申请ohos.permission.DISTRIBUTED_DATASYNC权限,以便允许不同设备间的数据交换。示例代码如下:

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

 

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; 
}

 

创建成功后,借助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; 
}

 

说明:
SINGLE_VERSION分布式数据库是指数据在本地保存是以单个KV条目为单位的方式保存,对每个Key最多只保存一个条目项,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。

 

最后是订阅分布式数据库中数据变化,方法如下:

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

 

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); 
}

 

 

数据查询

 

分布式数据库中的数据查询是根据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(); 
}

 

 说明:
以上代码除查询外,还有部分场景业务代码。

 

数据删除

 

对于分布式数据库的删除操作,可以直接调用deleteKvStore()方法,但是需要传递事先定义好的STORE_ID参数(具体定义参考下文完整代码),示例代码如下:

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

 

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); 
}

 

 说明:
以上代码除数据同步外,还有部分场景业务代码。

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>

 

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>

 

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>

 

随后在“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>

 

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>

 

业务逻辑代码

 

在"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; 
    } 
} 

 

在"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; 
    } 
}

 

在"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); 
    } 
}

 

 

在"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); 
    } 
}

 

 

最后在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); 
            } 
        } 
    } 
}

 

恭喜您
通过本教程的学习,您已经学会了分布式数据库服务的基础操作(创建、新增、删除、同步)。


 

 

 

已于2022-5-5 14:18:33修改
3
收藏 2
回复
举报
回复
    相关推荐