HarmonyOS分布式應用智能三角警示牌解讀
前言
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);
- }
- }