前言
HarmonyOS是 一款面向万物互联时代的、全新的分布式操作系统,其分布式技术能力(分布式软总线、分布式设备虚拟化、分布式数据管理、分布式任务调度)一直受到广大开发者的极大关注,使用户对HarmonyOS有着很高的赞许。
我们开发的《分布式智能三角警示牌应用》,以在日常生活中,公路上发生交通事故时通常是事故相关人员手持三角反光警示牌步行至目的地处放置,人为放置具有引发二次事故的风险,因此我们设计了智能移动三角警示牌以解决该问题。本智能三角警示牌通过手机HAP可以与其相连,控制运动方向和速度,使其停放在事故现场后方合适的位置,从而能够保障用户的人身和财产安全。
当在控制警示牌运动过程中,有紧急事情或其它情况,可以将当前的操作流转到另外一台设备中进行操作,其运动轨迹就是通过分布式数据服务来保证两台设备间数据的一致性。
效果展示
一、创建“智能三角警示牌”HAP工程
1、安装和配置DevEco Studio
2.1 Release
安装的链接:https://developer.harmonyos.com/cn/develop/deveco-studio
IDE的使用指南,很详细:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/tools_overview-0000001053582387
我的本案例使用的最新的 2.1.0.501版本,SDK:API Version 5
2、选择一个模版,创建一个Java Phone应用
==点击Next ==
点击Finish完成创建HAP工程
3、智能三角警示牌应用包结构
首先完成智能三角警示牌应用包结构设计,结构如下:
二、智能三角警示牌应用核心代码实现
1、config.json权限配置
- "reqPermissions": [
- {
- "name": "ohos.permission.INTERNET"
- },
- {
- "name": "ohos.permission.GET_NETWORK_INFO"
- },
- {
- "name": "ohos.permission.MICROPHONE"
- },
- {
- "name": "android.permission.RECORD_AUDIO"
- },
- {
- "name": "ohos.permission.DISTRIBUTED_DATASYNC"
- },
- {
- "name": "ohos.permission.servicebus.ACCESS_SERVICE"
- },
- {
- "name": "com.huawei.hwddmp.servicebus.BIND_SERVICE"
- },
- {
- "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
- },
- {
- "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
- },
- {
- "name": "ohos.permission.GET_BUNDLE_INFO"
- },
- {
- "name": "ohos.p
- ermission.LOCATION"
- }
- ]
2、分布式数据服务核心代码
- import com.google.gson.Gson;
- import com.google.gson.reflect.TypeToken;
- import com.isoftstone.smartcar.app.common.Constant;
- import com.isoftstone.smartcar.app.model.DrivingMap;
- import com.isoftstone.smartcar.app.model.DrivingRecord;
- import com.isoftstone.smartcar.app.model.ReportRecord;
- import com.isoftstone.smartcar.app.utils.DrivingReportComparator;
- import com.isoftstone.smartcar.app.utils.ReportRecordComparator;
- import com.isoftstone.smartcar.app.utils.StringUtils;
- import ohos.app.Context;
- 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;
- /**
- * 分布式数据库类服务
- */
- public class SmartShareService {
- private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "SmartshareService");
- private static SmartShareService smartShareService;
- private static SingleKvStore singleKvStore;
- private static KvManager kvManager;
- private final Context context;
- public static SmartShareService getInstance(Context context) {
- if (smartShareService == null) {
- smartShareService = new SmartShareService(context);
- }
- return smartShareService;
- }
- private SmartShareService(Context context){
- this.context = context;
- }
- /**
- * 分布式数据库初始化
- */
- public void init() {
- KvManagerConfig config = new KvManagerConfig(context);
- kvManager = KvManagerFactory.getInstance().createKvManager(config);
- Options options = new Options(); options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION).setAutoSync(true);
- singleKvStore = kvManager.getKvStore(options, Constant.SMART_SHARE_NAME);
- HiLog.info(label,"初始化成功!");
- //return singleKvStore;
- }
- /**
- * 新增行驶记录
- * @param drivingRecord 行驶记录对象
- */
- public void insertDrivingRecord(DrivingRecord drivingRecord){
- Gson gson = new Gson();
- String resultJson = gson.toJson(drivingRecord); singleKvStore.putString(Constant.DRIVING_REPORT_PREFIX+drivingRecord.getId(),resultJson);
- HiLog.info(label,"新增行驶记录成功!");
- }
- /**
- * 批量新增行驶记录轨迹
- * @param drivingId 行驶记录标识
- * @param drivingMapLst 行驶记录轨迹列表
- */
- public void insertDrivingMap(String drivingId, List<DrivingMap> drivingMapLst){
- Gson gson = new Gson();
- String resultJson = gson.toJson(drivingMapLst); singleKvStore.putString(Constant.DRIVING_MAP_PREFIX+drivingId,resultJson);
- HiLog.info(label,"批量新增行驶记录轨迹成功!");
- }
- /**
- * 新增上报记录
- * @param drivingId 行驶记录标识
- * @param reportRecord 上报记录对象
- */
- public void insertReportRecord(String drivingId, ReportRecord reportRecord){
- Gson gson = new Gson();
- List<Entry> entrys = singleKvStore.getEntries(Constant.REPORT_RECORD_PREFIX+drivingId);
- if (entrys == null || entrys.size() == 0){
- List<ReportRecord> reportRecordLst = new ArrayList<>();
- reportRecordLst.add(reportRecord);
- String resultJson1 = gson.toJson(reportRecordLst); singleKvStore.putString(Constant.REPORT_RECORD_PREFIX+drivingId,resultJson1);
- HiLog.info(label,"新增上报记录成功!");
- } else {
- String resultJson = entrys.get(0).getValue().getString();
- List<ReportRecord> reportRecordLst = gson.fromJson(resultJson, new TypeToken<List<ReportRecord>>() {}.getType());
- reportRecordLst.add(reportRecord);
- String resultJson1 = gson.toJson(reportRecordLst);
- singleKvStore.putString(Constant.REPORT_RECORD_PREFIX+drivingId,resultJson1);
- HiLog.info(label,"新增上报记录列表成功!");
- }
- }
- /**
- * 设置保险电话
- * @param key 保险key
- * @param telphone 保险key对应的值
- */
- public void setupInsuranceTelphone(String key,String telphone){
- singleKvStore.putString(Constant.TEL_PREFIX+key,telphone);
- HiLog.info(label,"设置保险电话成功!");
- }
- /**
- * 获取保险电话
- * @param key 保险电话key
- * @return 保险电话
- */
- public String getInsuranceTelphone(String key){
- String tel = "";
- List<Entry> entrys = singleKvStore.getEntries(Constant.TEL_PREFIX+key);
- if (entrys != null && entrys.size()>0) {
- tel = entrys.get(0).getValue().getString();
- HiLog.info(label,"获取保险电话成功!"+tel);
- } else {
- HiLog.info(label,"没有获取保险电话!");
- }
- return tel;
- }
- /**
- * 设置IP
- * @param key IP的key
- * @param value IP的value
- */
- public void setIp(String key,String value){
- singleKvStore.putString(Constant.IP_PREFIX+key,value);
- HiLog.info(label,"设置IP成功!");
- }
- /**
- * 获取IP
- * @param key IP的key
- * @return IP的值
- */
- public String getIp(String key){
- String tmpIp = "";
- List<Entry> entrys = singleKvStore.getEntries(Constant.IP_PREFIX+key);
- if (entrys != null && entrys.size()>0) {
- tmpIp = entrys.get(0).getValue().getString();
- HiLog.info(label,"获取IP成功!"+tmpIp);
- } else {
- HiLog.info(label,"没有获取到IP!");
- }
- return tmpIp;
- }
- /**
- * 获取行驶记录列表
- * @return 行驶记录列表
- */
- public List<DrivingRecord> getDrivingRecords(){
- List<DrivingRecord> drivingReporList = new ArrayList<>();
- List<Entry> entrys = singleKvStore.getEntries(Constant.DRIVING_REPORT_PREFIX);
- for(Entry entry:entrys){
- String key = entry.getKey();
- String value = entry.getValue().getString();
- HiLog.info(label,"获取到行驶记录的数据:key:" + key+",value:"+value);
- Gson gson = new Gson();
- DrivingRecord drivingRecord = gson.fromJson(value, DrivingRecord.class);
- //HiLog.info(label,drivingRecord.getId());
- drivingReporList.add(drivingRecord);
- }
- //排序
- if (drivingReporList.size() > 0) {
- DrivingReportComparator drivingReportComparator = new DrivingReportComparator();
- drivingReporList.sort(drivingReportComparator);
- }
- return drivingReporList;
- }
- /**
- * 获取行驶记录轨迹列表
- * @param drivingId 行驶记录标识
- * @return 行驶记录轨迹列表
- */
- public List<DrivingMap> getDrivingMap(String drivingId){
- String resultJson = singleKvStore.getString(Constant.DRIVING_MAP_PREFIX+drivingId);
- Gson gson = new Gson();
- return gson.fromJson(resultJson, new TypeToken<List<DrivingMap>>() {}.getType());
- }
- /**
- * 获取上报记录列表
- * @param drivingId 行驶记录标识
- * @return 上报记录列表
- */
- public List<ReportRecord> getReportRecords(String drivingId){
- List<Entry> entrys = singleKvStore.getEntries(Constant.REPORT_RECORD_PREFIX+drivingId);
- if (entrys == null || entrys.size() == 0){
- HiLog.info(label,"获取上报记录为空!");
- return null;
- } else {
- Gson gson = new Gson();
- Entry entry = entrys.get(0);
- String resultJson = entry.getValue().getString();
- List<ReportRecord> reportRecordLst = gson.fromJson(resultJson, new TypeToken<List<ReportRecord>>() {}.getType());
- HiLog.info(label,"获取上报记录成功!"+reportRecordLst.size());
- if (reportRecordLst!=null && reportRecordLst.size() > 0) {
- //排序
- ReportRecordComparator reportRecordComparator = new ReportRecordComparator();
- reportRecordLst.sort(reportRecordComparator);
- }
- return reportRecordLst;
- }
- }
- /**
- * 同步数据
- */
- public void syncData() {
- List<DeviceInfo> deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER);
- List<String> deviceIdList = new ArrayList<>();
- String deviceId;
- for (DeviceInfo deviceInfo : deviceInfoList) {
- deviceId = deviceInfo.getId();
- HiLog.info(label,"deviceId = " + deviceId);
- deviceIdList.add(deviceId);
- }
- HiLog.info(label,"deviceIdList.size() = " + deviceIdList.size());
- if (deviceIdList.size() > 0) {
- singleKvStore.sync(deviceIdList, SyncMode.PUSH_ONLY);
- } else {
- HiLog.error(label,"没有共享设备");
- }
- }
- /**
- * 注册回调接口
- * @param kvStoreObserver kvStore对象
- */
- public void registerCallback(KvStoreObserver kvStoreObserver) {
- singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, kvStoreObserver);
- }
- /**
- * 清空数据
- */
- public void clearAllData() {
- List<Entry> entrys = singleKvStore.getEntries("");
- if (entrys!=null && entrys.size()>0){
- for(Entry entry:entrys){
- singleKvStore.delete(entry.getKey());
- }
- HiLog.info(label,"清空数据成功");
- } else {
- HiLog.info(label,"没有数据要清空");
- }
- }
- /**
- * 从现有的行驶记录中获取drivingId
- * @return 返回行驶记录标识
- */
- public String getDrivingId(){
- String drivingId = "";
- List<Entry> entrys = singleKvStore.getEntries(Constant.DRIVING_REPORT_PREFIX);
- if (entrys != null && entrys.size() > 0){
- List<DrivingRecord> drivingReporList = new ArrayList<>();
- for(Entry entry:entrys){
- String value = entry.getValue().getString();
- Gson gson = new Gson();
- DrivingRecord drivingRecord = gson.fromJson(value, DrivingRecord.class);
- String dateStr = drivingRecord.getDrivingDate();
- if (StringUtils.isDiffHour(dateStr)){
- drivingReporList.add(drivingRecord);
- }
- HiLog.info(label,drivingRecord.getId());
- drivingReporList.add(drivingRecord);
- }
- if (drivingReporList.size() > 0) {
- //排序
- DrivingReportComparator drivingReportComparator = new DrivingReportComparator();
- drivingReporList.sort(drivingReportComparator);
- drivingId = drivingReporList.get(0).getId();
- HiLog.info(label,"找到符合条件的drivingId:"+drivingId);
- } else {
- HiLog.info(label,"没有找到符合条件的drivingId");
- }
- } else {
- HiLog.info(label,"行驶记录为空,没有找到符合条件的drivingId");
- }
- return drivingId;
- }
- }
3、行驶记录代码
- import com.isoftstone.smartcar.app.ResourceTable;
- import com.isoftstone.smartcar.app.model.DrivingRecord;
- import com.isoftstone.smartcar.app.provider.DrivingRecordProvider;
- import com.isoftstone.smartcar.app.service.SmartShareService;
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.aafwk.content.Operation;
- import ohos.agp.components.Component;
- import ohos.agp.components.Image;
- import ohos.agp.components.ListContainer;
- import java.util.List;
- /**
- * 行驶记录
- */
- public class DrivingRecordsAbilitySlice extends AbilitySlice implements Component.ClickedListener {
- private ListContainer lcRecords;
- private SmartShareService shareService;
- private List<DrivingRecord> drivingRecordList;
- private DrivingRecordProvider drivingRecordProvider;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_driving_records);
- initUI();
- }
- private void initUI() {
- shareService = SmartShareService.getInstance(this);
- shareService.init();
- Image iBack = (Image) findComponentById(ResourceTable.Id_i_back);
- iBack.setClickedListener(this);
- lcRecords = (ListContainer) findComponentById(ResourceTable.Id_lc_records);
- drivingRecordList = getData();
- drivingRecordProvider = new DrivingRecordProvider(drivingRecordList, this);
- lcRecords.setItemProvider(drivingRecordProvider);
- lcRecords.setItemClickedListener(new ListContainer.ItemClickedListener() {
- @Override
- public void onItemClicked(ListContainer listContainer, Component component, int i, long l) {
- Intent intent = new Intent();
- DrivingRecord drivingRecord = (DrivingRecord) drivingRecordProvider.getItem(i);
- intent.setParam("drivingId", drivingRecord.getId());
- intent.setParam("lat", drivingRecord.getLatitude());
- intent.setParam("lng", drivingRecord.getLongitude());
- Operation operation = new Intent.OperationBuilder()
- .withDeviceId("")
- .withBundleName("com.isoftstone.smartcar.app")
- .withAbilityName("com.isoftstone.smartcar.app.DrivingRecordsDetailAbility")
- .build();
- intent.setOperation(operation);
- startAbility(intent);
- //terminate();
- }
- });
- }
- @Override
- public void onActive() {
- super.onActive();
- drivingRecordList = getData();
- drivingRecordProvider = new DrivingRecordProvider(drivingRecordList, this);
- lcRecords.setItemProvider(drivingRecordProvider);
- }
- @Override
- public void onForeground(Intent intent) {
- super.onForeground(intent);
- }
- @Override
- public void onClick(Component component) {
- if (component.getId() == ResourceTable.Id_i_back) {
- terminateAbility();
- }
- }
- private List<DrivingRecord> getData() {
- return shareService.getDrivingRecords();
- }
- }
4、行驶记录详情代码
- import com.isoftstone.smartcar.app.ResourceTable;
- import com.isoftstone.smartcar.app.model.DrivingMap;
- import com.isoftstone.smartcar.app.model.ReportRecord;
- import com.isoftstone.smartcar.app.provider.ReportRecordProvider;
- import com.isoftstone.smartcar.app.service.SmartShareService;
- import com.isoftstone.smartcar.app.utils.CoordinateConverter;
- import com.isoftstone.smartcar.app.widget.carmap.LatLng;
- import com.isoftstone.smartcar.app.widget.carmap.TinyMap;
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.agp.components.Component;
- import ohos.agp.components.Image;
- import ohos.agp.components.ListContainer;
- import ohos.agp.utils.Point;
- import ohos.hiviewdfx.HiLog;
- import ohos.hiviewdfx.HiLogLabel;
- import ohos.multimodalinput.event.KeyEvent;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Timer;
- import java.util.TimerTask;
- /**
- * 行驶记录详情
- */
- public class DrivingRecordsDetailAbilitySlice extends AbilitySlice implements Component.ClickedListener {
- private static final HiLogLabel logLabel = new HiLogLabel(HiLog.LOG_APP, 0x00100, "DrivingRecordsDetailAbilitySlice");
- private TinyMap map;
- private String drivingId;
- private SmartShareService shareService;
- @Override
- protected void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_driving_records_detail);
- initUI(intent);
- }
- private void initUI(Intent intent) {
- Image iBack = (Image) findComponentById(ResourceTable.Id_i_back);
- iBack.setClickedListener(this);
- map = (TinyMap) findComponentById(ResourceTable.Id_map);
- ListContainer reportListContainer = (ListContainer) findComponentById(ResourceTable.Id_report_records);
- drivingId = intent.getStringParam("drivingId");
- shareService = SmartShareService.getInstance(this);
- shareService.init();
- new Timer().schedule(new TimerTask() {
- @Override
- public void run() {
- getUITaskDispatcher().asyncDispatch(new Runnable() {
- @Override
- public void run() {
- setMap();
- }
- });
- }
- },500);
- List<ReportRecord> reportRecords = shareService.getReportRecords(drivingId);
- ReportRecordProvider reportRecordProvider = new ReportRecordProvider(reportRecords, this);
- reportListContainer.setItemProvider(reportRecordProvider);
- }
- @Override
- public void onClick(Component component) {
- if (component.getId() == ResourceTable.Id_i_back) {//present(new DrivingRecordsAbilitySlice(), new Intent());
- terminate();
- }
- }
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
- HiLog.error(logLabel,keyEvent.getKeyCode()+"");
- if (keyCode==KeyEvent.KEY_BACK){
- //present(new DrivingRecordsAbilitySlice(), new Intent());
- terminate();
- return true;
- }
- return super.onKeyDown(keyCode, keyEvent);
- }
- private LatLng WGS84ToMercator(LatLng latLng) {
- return CoordinateConverter.WGS84ToMercator(latLng.getLng(), latLng.getLat());
- }
- private void setMap() {
- map.initMap();
- List<DrivingMap> drivingMaps = shareService.getDrivingMap(drivingId);
- LatLng startLatLng0 = new LatLng(Double.parseDouble(drivingMaps.get(0).getLatitude()), Double.parseDouble(drivingMaps.get(0).getLongitude()));
- LatLng startLatLng = new LatLng((float) WGS84ToMercator(startLatLng0).getLat(), (float) WGS84ToMercator(startLatLng0).getLng());
- map.setCenterPoint((float) startLatLng.getLng(), (float) startLatLng.getLat());
- LatLng endLatLng0 = new LatLng(Double.parseDouble(drivingMaps.get(drivingMaps.size() - 1).getLatitude()), Double.parseDouble(drivingMaps.get(drivingMaps.size() - 1).getLongitude()));
- LatLng endLatLng = new LatLng((float) WGS84ToMercator(endLatLng0).getLat(), (float) WGS84ToMercator(endLatLng0).getLng());
- map.setStartElement((float) startLatLng.getLng(), (float) startLatLng.getLat(), ResourceTable.Media_start_location);
- map.setEndElement((float) endLatLng.getLng(), (float) endLatLng.getLat(), ResourceTable.Media_end_location);
- List<LatLng> latLngs = new ArrayList<>();
- for (DrivingMap drivingMap : drivingMaps) {
- LatLng latLng = new LatLng(Double.parseDouble(drivingMap.getLatitude()), Double.parseDouble(drivingMap.getLongitude()));
- Point p = new Point((float) WGS84ToMercator(latLng).getLng(), (float) WGS84ToMercator(latLng).getLat());
- latLngs.add(new LatLng(p.getPointY(), p.getPointX()));
- }
- map.setPaths(latLngs);
- }
- }