#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读 原创 精华

软通动力HOS
发布于 2021-12-13 11:34
浏览
9收藏

【本文正在参与51CTO HarmonyOS技术社区创作者激励计划-星光计划2.0】

#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区

引言

分布式数据服务(Distributed Data Service,DDS) 为应用程序提供不同设备间数据库数据分布式的能力。通过调用分布式数据接口,应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组,分布式数据服务对属于不同应用的数据进行隔离,保证不同应用之间的数据不能通过分布式数据服务互相访问。在通过可信认证的设备间,分布式数据服务支持应用数据相互同步,为用户提供在多种终端设备上最终一致的数据访问体验。

功能介绍

此次基于HarmonyOS的分布式数据服务能力,一方面模拟农业大棚的温度、湿度、二氧化碳浓度等数据的采集,并在手机端进行采集数据展示;另一方面,可以把手机端的数据,迁移到其他设备(如智慧屏、手表、PAD等),可以做一些数据分析展示。

前提:

在不同设备之间,要实现分布式数据服务的同步能力,需要同一个华为账号登录、并一个应用包名、同一个网络之间进行,也可以是两个设备同时开启蓝牙。

开发指南

1.在config.json中添加permisssion权限

// 添加在abilities同一目录层级

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

2.在MainAbility中添加权限

@Override
public void onStart(Intent intent) {
  super.onStart(intent);
  super.setMainRoute(MainAbilitySlice.class.getName());
  //实现Ability的代码中显式声明需要使用多设备协同访问的权限
  requestPermissionsFromUser(new String[]{
      "ohos.permission.DISTRIBUTED_DATASYNC"}, 0);

}

3.根据配置构造分布式数据库管理类实例KvManager以及创建分布式数据库对象SingleKvStore

//实现数据库的初始化

// 初入的参数context: Context context = getApplicationContext()获得;storeId为分布式数据库id,String类型,可自行定义,例如“testApp”。
public static SingleKvStore initOrGetDB(Context context, String storeId) {
  KvManagerConfig kvManagerConfig = new KvManagerConfig(context);
  kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
  Options options = new Options();
  options.setCreateIfMissing(true)
    .setEncrypt(false)
    .setKvStoreType(KvStoreType.SINGLE_VERSION) //数据库类型:单版本分布式数据库
    .setAutoSync(true); //自动同步为true,手动同步为false
  singleKvStore = kvManager.getKvStore(options, storeId);
  return singleKvStore;
}

4.将数据写入单版本分布式数据库

//以key-value形式存储到分布式数据库
try {
  //将采集的数据以key-value形式存入分布式数据库中
  DataModle dataModle=new DataModle();
  dataModle.setTemp(temp);
  dataModle.setHumi(humi);
  dataModle.setCo2(co2);
  String jsonString= ZSONObject.toZSONString(dataModle);
  singleKvStore.putString("data",jsonString);
} catch (KvStoreException e) {
  LogUtils.debug(TAG, "DataServiceAbility::updateData()"+e.getMessage());
}

5.订阅分布式数据变化。客户端需要实现KvStoreObserver接口,监听数据变化

//订阅类型SubscribeType.SUBSCRIBE_TYPE_ALL意思可以同步到本机和其他外围设备
  innerKvStoreObserver = new InnerKvStoreObserver();
  singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, innerKvStoreObserver);
} catch (KvStoreException e) {
  e.printStackTrace();
}

public class InnerKvStoreObserver implements KvStoreObserver {

  @Override
  public void onChange(ChangeNotification changeNotification) {
    //刷新页面上的数据,同样有一个坑,onChange方法实质上,在一个子线程里执行
    MainAbilitySlice.taskDispatcher.asyncDispatch(() -> {
      //在这里执行页面ui组件的显示刷新
      flushUIData();
    });
  }
}

6.获取分布式数据库数据

 //查询分布式数据的数据,获取数据可以通过get(String key)或者 getEntries(String key)方法获取数据
List<Entry> entries = singleKvStore.getEntries("data");
if (entries.size() > 0) {
  ZSONObject zsonObject = ZSONObject.stringToZSON(entries.get(0).getValue().getString());
  double temp = zsonObject.getDouble("temp");
  double humi = zsonObject.getDouble("humi");
  double co2 = zsonObject.getDouble("co2");
  String strTemp = String.format("%.1f", temp);
  String strHumi = String.format("%.1f", humi);
  String strCO2 = String.format("%.1f", co2);
  tvTemp.setText(strTemp+"℃");
  tvHumi.setText(strHumi+"%RH");
  tvCo2.setText(strCO2+"ppm");
}

7.解除订阅,一般在页面销毁时调用,也就是在onStop()中调用

if (singleKvStore != null) {
  singleKvStore.unSubscribe(innerKvStoreObserver);
}

8.同步数据到其他设备。获取已连接的设备列表,选择同步方式进行数据同步

List<DeviceInfo> onlineDevices = DeviceManager
    .getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
List<String> deviceIdList = new ArrayList<>();
for (DeviceInfo deviceInfo : deviceInfoList) {
    deviceIdList.add(deviceInfo.getId());
}
//迁移到指定设备,传入设备ID列表
singleKvStore.sync(deviceIdList, SyncMode.PUSH_ONLY);

项目中采用在后台service中开启定时任务,模拟农业大棚采集数据,实时保存数据到分布式数据库,然后在主界面,监听数据变化,实时更新数据。当选择迁移的设备时,就可以把数据迁移到相应设备。
#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区
手机侧应用刚打开时界面
#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区
TV侧应用刚打开时界面
#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区
点击右上角迁移按钮,并选择迁移设备(P40-0036)
#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区
#星光计划2.0#HarmonyOS分布式应用农业大棚数据监测解读-鸿蒙开发者社区
迁移后的左侧设备数据和右侧设备数据就会同步一致

附上源码

手机端

1. PhoneAbilitySlice

public class PhoneAbilitySlice extends AbilitySlice {
  private SingleKvStore singleKvStore;
  private InnerKvStoreObserver innerKvStoreObserver;
  private Intent serviceIntent;
  private Text tvTemp;
  private Text tvHumi;
  private Text tvCo2;
  private DeviceData chooseDevice;
  private DevicesProvider devicesProvider;
  private CommonDialog commonDialog;
  private String TAG="MainAbilitySlice";
  private List<String>deviceIdList;
  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);
    //设置沉浸式状态栏  getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
    initView();
    initService();
    try {
      //获取数据库
      singleKvStore = DBUtils.initOrGetDB(this, DBUtils.KV_STORE_NAME);
      innerKvStoreObserver = new InnerKvStoreObserver();
      //订阅分布式数据库
      singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, innerKvStoreObserver);
    } catch (KvStoreException e) {
      LogUtils.debug(TAG, "MainAbilitySlice::onStart/"+e.getMessage());
    }
  }
  private void initService() {
    //启动ServiceAbility
    serviceIntent = new Intent();
    Operation operation = new Intent.OperationBuilder()
        .withDeviceId("")
        .withBundleName("com.isoftstone.distributeddata")
        .withAbilityName("com.isoftstone.distributeddata.DataServiceAbility")
        .build();
    serviceIntent.setOperation(operation);
    startAbility(serviceIntent);
  }
  private void initView() {
    tvTemp = (Text) findComponentById(ResourceTable.Id_text_temp);
    tvHumi = (Text) findComponentById(ResourceTable.Id_text_humi);
    tvCo2 = (Text) findComponentById(ResourceTable.Id_text_co2);
    Button bt = (Button) findComponentById(ResourceTable.Id_bt_continue);
    bt.setClickedListener(component -> {
      if (component.getId() == ResourceTable.Id_bt_continue) {
        //查看在线设备
        List<DeviceInfo> onlineDevices = DeviceManager
            .getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
        List<DeviceData> deviceDatas = new ArrayList<>();
        if (onlineDevices == null || onlineDevices.size() < 1) {
          CustomerDialog.showToastDialog(getAbility(), "无组网在线设备");
        } else {
          for (DeviceInfo deviceInfo : onlineDevices) {
            deviceDatas.add(new DeviceData(false, deviceInfo));
          }
          showDevices(deviceDatas);
        }
      }
    });
  }
  private void showDevices(List<DeviceData> deviceDatas) {
    chooseDevice = null;
    commonDialog = new CommonDialog(this);
    Component component = LayoutScatter.getInstance(this)
        .parse(ResourceTable.Layout_dialog_layout_device, null, true);
    ListContainer listContainer = (ListContainer) component.findComponentById(ResourceTable.Id_list_container_device);
    devicesProvider = new DevicesProvider(this, deviceDatas);
    listContainer.setItemProvider(devicesProvider);
    listContainer.setItemClickedListener((listContainer1, component1, position, l) -> {
      chooseDevice = deviceDatas.get(position);
      for (int i = 0; i < deviceDatas.size(); i++) {
        if (i == position) {
          deviceDatas.set(i, new DeviceData(true, deviceDatas.get(i).getDeviceInfo()));
        } else {
          deviceDatas.set(i, new DeviceData(false, deviceDatas.get(i).getDeviceInfo()));
        }
      }
      devicesProvider = new DevicesProvider(this, deviceDatas);
      listContainer1.setItemProvider(devicesProvider);
    });
    Text tvCancle = (Text) component.findComponentById(ResourceTable.Id_operate_no);
    Text tvSure = (Text) component.findComponentById(ResourceTable.Id_operate_yes);

    tvCancle.setClickedListener(component12 -> commonDialog.destroy());

    tvSure.setClickedListener(component13 -> {
      if (chooseDevice == null) {
        CustomerDialog.showToastDialog(this, "请选择设备");
      } else {
        try {
          deviceIdList=new ArrayList<>();
          deviceIdList.add(chooseDevice.getDeviceInfo().getDeviceId());
          //手动同步的设备列表
          singleKvStore.sync(deviceIdList, SyncMode.PUSH_ONLY);
          commonDialog.destroy();
        } catch (IllegalStateException e) {
          //流转异常捕获,防止进程存在再次发起流转
          LogUtils.debug(TAG, "MainAbilitySlice::singleKvStore.sync()/"+e.getMessage());
        }
      }
    });
    commonDialog.setSize(MATCH_PARENT, MATCH_CONTENT);
    commonDialog.setAlignment(LayoutAlignment.BOTTOM);
    commonDialog.setCornerRadius(10);
    commonDialog.setAutoClosable(true);
    commonDialog.setContentCustomComponent(component);
    commonDialog.setTransparent(true);
    commonDialog.show();
  }
  public class InnerKvStoreObserver implements KvStoreObserver {

    @Override
    public void onChange(ChangeNotification changeNotification) {
      //onChange方法实质上,在一个子线程里执行
      getUITaskDispatcher().asyncDispatch(() -> {
        //在这里执行页面ui组件的显示刷新
        asyncUpdateData();
      });
    }
  }
  public void asyncUpdateData(){
    //查询分布式数据的数据
    List<Entry> entries = singleKvStore.getEntries("data");
    if (entries.size() > 0) {
      ZSONObject zsonObject = ZSONObject.stringToZSON(entries.get(0).getValue().getString());
      double temp = zsonObject.getDouble("temp");
      double humi = zsonObject.getDouble("humi");
      double co2 = zsonObject.getDouble("co2");
      String strTemp = String.format("%.1f", temp);
      String strHumi = String.format("%.1f", humi);
      String strCO2 = String.format("%.1f", co2);
      tvTemp.setText(strTemp+"℃");
      tvHumi.setText(strHumi+"%RH");
      tvCo2.setText(strCO2+"ppm");
      //手动同步的设备列表
      if(singleKvStore!=null){
        if(deviceIdList!=null&&deviceIdList.size()>0){
          singleKvStore.sync(deviceIdList, SyncMode.PUSH_ONLY);
        }
      }
    }
  }

  @Override
  public void onActive() {
    super.onActive();
  }
  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }
  @Override
  protected void onStop() {
    super.onStop();
    //销毁service
    stopAbility(serviceIntent);
    //删除数据库
    DBUtils.clearDB();
    //解除订阅
    if (singleKvStore != null) {
      if(innerKvStoreObserver!=null){
        singleKvStore.unSubscribe(innerKvStoreObserver);
      }
    }
  }
}

2. DataServiceAbility

public class DataServiceAbility extends Ability {
  private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
  private SingleKvStore singleKvStore;
  private NotificationRequest request;
  private Timer mTimer;
  private TimerTask mTimerTask;
  private String TAG="DataServiceAbility";
  @Override
  public void onStart(Intent intent) {
    LogUtils.debug(TAG, "DataServiceAbility::onStart");
    super.onStart(intent);
    //创建前台service
    createForeService();
    try {
      singleKvStore = DBUtils.initOrGetDB(this, DBUtils.KV_STORE_NAME);
    } catch (Exception e) {
      LogUtils.debug(TAG, "DataServiceAbility::onStart()"+e.getMessage());
    }
    //每隔10秒,模拟传感器采集一次大棚数据。
    if(mTimer==null){
      mTimer=new Timer();
    }
    if(mTimerTask==null){
      mTimerTask=new TimerTask() {
        @Override
        public void run() {
          updateData();
        }
      };
    }
    mTimer.schedule(mTimerTask,0,1000*10);
  }
  private void updateData() {
    //获取随机温度0-100;
    double temp= new Random().nextDouble()*100;
    //获取随机湿度0-100;
    double humi= new Random().nextDouble()*100;
    //获取随机CO2浓度0-1000
    double co2= new Random().nextDouble()*1000;
    try {
      //将采集的数据以key-value形式存入分布式数据库中
      DataModle dataModle=new DataModle();
      dataModle.setTemp(temp);
      dataModle.setHumi(humi);
      dataModle.setCo2(co2);
      String jsonString= ZSONObject.toZSONString(dataModle);
      singleKvStore.putString("data",jsonString);
    } catch (KvStoreException e) {
      LogUtils.debug(TAG, "DataServiceAbility::updateData()"+e.getMessage());
    }
  }
  private void createForeService() {
    // 创建通知,其中1005为notificationId
    request = new NotificationRequest(1005);
    NotificationRequest.NotificationNormalContent content = new NotificationRequest.NotificationNormalContent();
    content.setTitle("农业大棚").setText("数据采集服务开启中");
    NotificationRequest.NotificationContent notificationContent = new NotificationRequest.NotificationContent(content);
    request.setContent(notificationContent);
    //绑定通知,1005为创建通知时传入的notificationId
    keepBackgroundRunning(1005, request);
  }
  @Override
  public void onBackground() {
    super.onBackground();
    LogUtils.debug(TAG, "DataServiceAbility::onBackground()");
  }

  @Override
  public void onStop() {
    super.onStop();
    if (mTimerTask != null) {
      mTimerTask.cancel();
      mTimerTask=null;
    } if (mTimer != null) {
      mTimer.cancel();
      mTimer=null;
    }
    //停止前台Service。
    cancelBackgroundRunning();
    LogUtils.debug(TAG, "DataServiceAbility::onStop()");
  }

  @Override
  public void onCommand(Intent intent, boolean restart, int startId) {
  }
  @Override
  public IRemoteObject onConnect(Intent intent) {
    return null;
  }
  @Override
  public void onDisconnect(Intent intent) {
  }
}

3.DBUtils

public class DBUtils {
  private static KvManager kvManager;
  private static SingleKvStore singleKvStore;
  public static String KV_STORE_NAME="farm_data";
  //具体的实现数据库的初始化
  public static SingleKvStore initOrGetDB(Context context, String storeId) {
    KvManagerConfig kvManagerConfig = new KvManagerConfig(context);
    kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
    Options options = new Options();
    options.setCreateIfMissing(true)
        .setEncrypt(false)
        .setKvStoreType(KvStoreType.SINGLE_VERSION)
        .setAutoSync(false);//自动同步为true,手动同步为false
    singleKvStore = kvManager.getKvStore(options, storeId);
    return singleKvStore;
  }
  // 如果数据库中的字段有修改,只能先关闭,后删除,然后重新创建才生效
  public static void clearDB() {
    kvManager.closeKvStore(singleKvStore);
    kvManager.deleteKvStore(KV_STORE_NAME);
  }
}

4. MainAbility

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setMainRoute(PhoneAbilitySlice.class.getName());
        //实现Ability的代码中显式声明需要使用多设备协同访问的权限
        requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC",}, 0);
    }
}

5. DataModle

public class DataModle {
  private double temp;
  private double humi;
  private double co2;
  public double getTemp() {
    return temp;
  }
  public void setTemp(double temp) {
    this.temp = temp;
  }

  public double getHumi() {
    return humi;
  }
  public void setHumi(double humi) {
    this.humi = humi;
  }
  public double getCo2() {
    return co2;
  }
  public void setCo2(double co2) {
    this.co2 = co2;
  }
}

6. DeviceData

public class DeviceData {
    private boolean isChecked;
    private DeviceInfo deviceInfo;
    /**
     * DeviceData
     *
     * @param isChecked isChecked
     * @param deviceInfo deviceInfo
     */
    public DeviceData(boolean isChecked, DeviceInfo deviceInfo) {
        this.isChecked = isChecked;
        this.deviceInfo = deviceInfo;
    }
    public DeviceInfo getDeviceInfo() {
        return deviceInfo;
    }
    public void setDeviceInfo(DeviceInfo deviceInfo) {
        this.deviceInfo = deviceInfo;
    }
    public boolean isChecked() {
        return isChecked;
    }
    public void setChecked(boolean checked) {
        isChecked = checked;
    }
}

7. DevicesProvider

public class DevicesProvider extends BaseItemProvider {

 private List<DeviceData> data;
 private LayoutScatter layoutScatter;

 public DevicesProvider(Context context, List<DeviceData> data) {
   this.data = data;
   this.layoutScatter = LayoutScatter.getInstance(context);
 }

 @Override
 public int getCount() {
   return data.size();
 }

 @Override
 public Object getItem(int i) {
   return data.get(i);
 }

 @Override
 public long getItemId(int i) {
   return i;
 }

 @Override
 public Component getComponent(int position, Component component,
     ComponentContainer componentContainer) {
   ViewHolder viewHolder;
   // component相当于Android中的view,其他的和Android中ListView的适配器adapter差不多。
   // 名字区别也不大,不过Android中ListView基本被淘汰了。
   if (component == null) {
     component = layoutScatter.parse(ResourceTable.Layout_dialog_device_item, null, false);
     viewHolder = new ViewHolder();
     viewHolder.imgType = (Image) component.findComponentById(ResourceTable.Id_item_type);
     viewHolder.tvName = (Text) component.findComponentById(ResourceTable.Id_item_name);
     viewHolder.imgCheck = (Image) component.findComponentById(ResourceTable.Id_item_check);
     component.setTag(viewHolder);
   } else {
     viewHolder = (ViewHolder) component.getTag();
   }
   DeviceData deviceData = data.get(position);
   DeviceType deviceType=deviceData.getDeviceInfo().getDeviceType();
   switch (deviceType){
     case SMART_WATCH:
       viewHolder.imgType.setPixelMap(ResourceTable.Media_dv_watch);
       break;
     case SMART_PAD:
       viewHolder.imgType.setPixelMap(ResourceTable.Media_dv_pad);
       break;
     case SMART_PHONE:
       viewHolder.imgType.setPixelMap(ResourceTable.Media_dv_phone);
       break;
   }
   viewHolder.tvName.setText(deviceData.getDeviceInfo().getDeviceName());
   if(deviceData.isChecked()){
viewHolder.imgCheck.setImageAndDecodeBounds(ResourceTable.Media_check2); }else {  viewHolder.imgCheck.setImageAndDecodeBounds(ResourceTable.Media_uncheck2);
   }
   return component;
 }

 /**
  * 类似于Android中的listView缓存。 将已经显示在屏幕上的item缓存在ViewHolder中,下次再次出现直接从缓存中读取
  */
 private static class ViewHolder {
   private Image imgType;
   private Text tvName;
   private Image imgCheck;
 }
}

8. CustomerDialog

public class CustomerDialog {
  public static void showToastDialog(Context context, String str) {
    DirectionalLayout toastLayout = (DirectionalLayout) LayoutScatter.getInstance(context)
        .parse(ResourceTable.Layout_toast_dialog, null, false);
    Text text = (Text) toastLayout.findComponentById(ResourceTable.Id_toast);
    text.setText(str);
    new ToastDialog(context)
        .setContentCustomComponent(toastLayout)
        .setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT,
            DirectionalLayout.LayoutConfig.MATCH_CONTENT)
        .setAlignment(LayoutAlignment.CENTER)
        .show();
  }
}

9. MyApplication

  @Override
  public void onInitialize() {
    super.onInitialize();
  }
}

10. config.json 文件

  "app": {
    "bundleName": " com.isoftstone.distributeddata ",
    "vendor": "isoftstone",
    "version": {
      "code": 1000000,
      "name": "1.0.0"
    }
  },
  "deviceConfig": {},
  "module": {
    "package": "com.isoftstone.distributeddata",
    "name": ".MyApplication",
    "mainAbility": "com.isoftstone.distributeddata.MainAbility",
    "deviceType": [
      "phone"
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry",
      "installationFree": false
    },
    "reqPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC"
      },
      {
//添加此权限,才能查找分布式在线设备
        "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
      },
      {
//将service设置为前台服务,需要添加的权限
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" 
      }
    ],
    "abilities": [
      {
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ],
        "orientation": "unspecified",
        "name": "com.isoftstone.distributeddata.MainAbility",
        "icon": "$media:icon",
        "description": "$string:mainability_description",
        "label": "$string:entry_MainAbility",
        "type": "page",
        "launchType": "standard"
      },
      {
        "name": "com.isoftstone.distributeddata.DataServiceAbility",
        "icon": "$media:icon",
        "description": "$string:dataserviceability_description",
        "type": "service",
        "visible": true,
        "backgroundModes": [
          "dataTransfer",
          "location"
        ]
      }

    ],
    "metaData": {
      "customizeData": [
        {
          "name": "hwc-theme",
          "value": "androidhwext:style/Theme.Emui.NoTitleBar",
          "extra": ""
        }
      ]
    }
  }
}

11.ability_main.xml布局文件

<?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="match_content"
    ohos:orientation="horizontal"
    ohos:top_padding="50vp"
    ohos:bottom_padding="20vp"
    ohos:left_padding="20vp"
    ohos:right_padding="20vp"
    ohos:background_element="$graphic:background_ability_main">
    <Text
      ohos:width="match_content"
      ohos:height="match_content"
      ohos:text="农业大棚数据监测"
      ohos:text_size="26vp"
      ohos:text_color="#ffffff"
      ohos:center_in_parent="true"/>
    <Button
      ohos:id="$+id:bt_continue"
      ohos:width="25vp"
      ohos:height="25vp"
      ohos:background_element="$media:conti"
      ohos:align_parent_right="true"
      ohos:vertical_center="true"/>
  </DependentLayout>
  <DependentLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:background_element="#f4f5f7"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="10vp"
    ohos:bottom_padding="10vp">

    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="温度:"
      ohos:text_color="#000000"
      ohos:text_size="18fp"
      ohos:vertical_center="true"/>

    <Text
      ohos:id="$+id:text_temp"
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="数据正在采集 "
      ohos:text_color="#00ff00"
      ohos:text_size="18fp"
      ohos:left_margin="50vp"
      ohos:vertical_center="true"/>
  </DependentLayout>

  <Component
    ohos:height="2vp"
    ohos:width="match_content"
    ohos:background_element="#FFFFFF"/>

  <DependentLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:background_element="#f4f5f7"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="10vp"
    ohos:bottom_padding="10vp">

    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="湿度:"
      ohos:text_color="#000000"
      ohos:text_size="18fp"
      ohos:vertical_center="true"/>

    <Text
      ohos:id="$+id:text_humi"
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="数据正在采集 "
      ohos:text_color="#00ff00"
      ohos:text_size="18fp"
      ohos:left_margin="50vp"
      ohos:vertical_center="true"/>
  </DependentLayout>

  <Component
    ohos:height="2vp"
    ohos:width="match_content"
    ohos:background_element="#FFFFFF"/>

  <DependentLayout
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:background_element="#f4f5f7"
    ohos:left_padding="15vp"
    ohos:right_padding="15vp"
    ohos:top_padding="10vp"
    ohos:bottom_padding="10vp">

    <Text
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="CO2:"
      ohos:text_color="#000000"
      ohos:text_size="18fp"
      ohos:vertical_center="true"/>

    <Text
      ohos:id="$+id:text_co2"
      ohos:height="match_content"
      ohos:width="match_content"
      ohos:text="数据正在采集 "
      ohos:text_color="#00ff00"
      ohos:text_size="18fp"
      ohos:left_margin="50vp"
      ohos:vertical_center="true"/>
  </DependentLayout>


</DirectionalLayout>

12. dialog_device_item.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="70vp"
    ohos:width="match_parent"
    ohos:orientation="horizontal">

    <Image
        ohos:id="$+id:item_type"
        ohos:height="45vp"
        ohos:width="50vp"
        ohos:image_src="$media:dv_phone"
        ohos:layout_alignment="vertical_center"
        ohos:left_margin="10vp"
        ohos:scale_mode="inside"/>

    <Text
        ohos:id="$+id:item_name"
        ohos:height="match_parent"
        ohos:width="0vp"
        ohos:max_text_lines="1"
        ohos:text="Huawei P40"
        ohos:text_alignment="vertical_center"
        ohos:text_size="15fp"
        ohos:weight="1"/>

    <Image
        ohos:id="$+id:item_check"
        ohos:height="30vp"
        ohos:width="30vp"
        ohos:image_src="$media:uncheck2"
        ohos:layout_alignment="vertical_center"
        ohos:right_margin="15vp"/>
</DirectionalLayout>

13.dialog_layout_device.xml

<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="340vp"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <DirectionalLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="$graphic:background_white_radius_10"
        ohos:bottom_margin="50vp"
        ohos:left_margin="20vp"
        ohos:orientation="vertical"
        ohos:right_margin="20vp">

        <Text
            ohos:height="50vp"
            ohos:width="match_parent"
            ohos:left_padding="20vp"
            ohos:text="迁移到其他设备"
            ohos:text_alignment="vertical_center"
            ohos:text_color="#000000"
            ohos:text_size="16fp"/>

        <ListContainer
            ohos:id="$+id:list_container_device"
            ohos:height="0vp"
            ohos:width="match_parent"
            ohos:weight="1"/>

        <DirectionalLayout
            ohos:height="50vp"
            ohos:width="match_parent"
            ohos:orientation="horizontal">

            <Text
                ohos:id="$+id:operate_no"
                ohos:height="match_parent"
                ohos:width="0vp"
                ohos:text="取消"
                ohos:text_alignment="center"
                ohos:text_color="#1e90ff"
                ohos:text_size="17fp"
                ohos:weight="1"/>

            <Component
                ohos:height="25vp"
                ohos:width="1vp"
                ohos:background_element="#cccccc"
                ohos:layout_alignment="vertical_center"/>

            <Text
                ohos:id="$+id:operate_yes"
                ohos:height="match_parent"
                ohos:width="0vp"
                ohos:text="确定"
                ohos:text_alignment="center"
                ohos:text_color="#1e90ff"
                ohos:text_size="17fp"
                ohos:weight="1"/>
        </DirectionalLayout>
    </DirectionalLayout>
</DirectionalLayout>

14. toast_dialog.xml

<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:orientation="vertical"
    ohos:background_element="$graphic:background_gray_circle">
    <Text
        ohos:id="$+id:toast"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:left_padding="16vp"
        ohos:right_padding="16vp"
        ohos:top_padding="4vp"
        ohos:bottom_padding="4vp"
        ohos:layout_alignment="center"
        ohos:text_size="20fp"/>
</DirectionalLayout>

TV端

1. TVAbilitySlice


    private Text tvTemp;
    private Text tvTempMax;
    private Text tvTempMin;

    private Text tvHumi;
    private Text tvHumiMax;
    private Text tvHumiMin;

    private Text tvCgas;
    private Text tvCgasMax;
    private Text tvCgasMin;

    private Text tvTempStatus;
    private Text tvHumiStatus;
    private Text tvCgasStatus;


    private ProgressBar rgbTem;
    private ProgressBar rgbHumi;
    private ProgressBar rgbCgas;

    private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x0001, "my_log");

    private double temp;
    private double humi;
    private double cGas;
    private SingleKvStore singleKvStore;
    private KvStoreObserverClient kvStoreObserverClient;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_tv);
        //设置沉浸式状态栏
        getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);

        tvTemp = (Text) findComponentById(ResourceTable.Id_tvTemp);
        tvTempMax = (Text) findComponentById(ResourceTable.Id_tvMaxTemp);
        tvTempMin = (Text) findComponentById(ResourceTable.Id_tvMinTemp);
        rgbTem = (RoundProgressBar) findComponentById(ResourceTable.Id_rgb_tem);

        tvHumi = (Text) findComponentById(ResourceTable.Id_tvHumi);
        tvHumiMax = (Text) findComponentById(ResourceTable.Id_tvMaxHumi);
        tvHumiMin = (Text) findComponentById(ResourceTable.Id_tvMinHumi);
        rgbHumi = (RoundProgressBar) findComponentById(ResourceTable.Id_rgb_humi);

        tvCgas = (Text) findComponentById(ResourceTable.Id_tvCgas);
        tvCgasMax = (Text) findComponentById(ResourceTable.Id_tvMaxCgas);
        tvCgasMin = (Text) findComponentById(ResourceTable.Id_tvMinCgas);
        rgbCgas = (RoundProgressBar) findComponentById(ResourceTable.Id_rgb_gas);

        tvTempStatus = (Text) findComponentById(ResourceTable.Id_tvTempStatus);
        tvHumiStatus = (Text) findComponentById(ResourceTable.Id_tvHumiStatus);
        tvCgasStatus = (Text) findComponentById(ResourceTable.Id_tvCgasStatus);

        try {
            KvManagerConfig config = new KvManagerConfig(getContext());
            KvManager kvManager = KvManagerFactory.getInstance().createKvManager(config);
            Options CREATE = new Options();
            CREATE.setCreateIfMissing(true).setEncrypt(false)
                .setKvStoreType(KvStoreType.SINGLE_VERSION)
                .setAutoSync(true);
            singleKvStore = kvManager.getKvStore(CREATE, DBUtils.KV_STORE_NAME);
            kvStoreObserverClient = new KvStoreObserverClient();
            singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, kvStoreObserverClient);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private class KvStoreObserverClient implements KvStoreObserver {

        @Override
        public void onChange(ChangeNotification notification) {
            //onChange方法实质上,在一个子线程里执行
            getUITaskDispatcher().asyncDispatch(() -> {
                //在这里执行页面ui组件的显示刷新
                asyncUpdateData();
            });
        }
    }


    public void asyncUpdateData(){
        //查询分布式数据的数据
        List<Entry> entries = singleKvStore.getEntries("data");
        if (entries.size() > 0) {
            ZSONObject zsonObject = ZSONObject.stringToZSON(entries.get(0).getValue().getString());
            double temp = zsonObject.getDouble("temp");
            double humi = zsonObject.getDouble("humi");
            double co2 = zsonObject.getDouble("co2");
            String strTemp = String.format("%.1f", temp);
            String strHumi = String.format("%.1f", humi);
            String strCO2 = String.format("%.1f", co2);
            initView(strTemp,strHumi,strCO2);

        }
    }

    private void initView(String strTemp,String strHumi,String strCO2) {
        temp = Double.valueOf(strTemp);
        int tempMax = 45;
        int tempMin = -10;

        humi = Double.valueOf(strHumi);
        int humiMax = 70;
        int humiMin = 10;

        cGas = Double.valueOf(strCO2);
        int cGasMax = 1000;

        if (temp > -100) {
            if (temp > tempMax || temp < tempMin) {
                tvTemp.setTextColor(Color.RED);
                tvTempStatus.setText("异常");
                tvTempStatus.setTextColor(Color.RED);
                rgbTem.setProgressColor(Color.RED);
            } else {
                tvTemp.setTextColor(Color.GREEN);
                tvTempStatus.setText("正常");
                tvTempStatus.setTextColor(Color.GREEN);
                rgbTem.setProgressColor(Color.GREEN);

            }
        } else {
            tvTemp.setTextColor(Color.BLACK);
            tvTempStatus.setTextColor(Color.BLACK);
            tvTempStatus.setText("未知");
            rgbTem.setProgressColor(Color.GREEN);

        }
        tvTempMax.setText(tempMax + "℃");
        tvTempMin.setText(tempMin + "℃");

        if (humi > -100) {
            if (humi > humiMax || humi < humiMin) {
                tvHumi.setTextColor(Color.RED);
                tvHumiStatus.setText("异常");
                tvHumiStatus.setTextColor(Color.RED);
                rgbHumi.setProgressColor(Color.RED);
            } else {
                tvHumi.setTextColor(Color.GREEN);
                tvHumiStatus.setText("正常");
                tvHumiStatus.setTextColor(Color.GREEN);
                rgbHumi.setProgressColor(Color.GREEN);
            }
        } else {
            tvHumi.setTextColor(Color.BLACK);
            tvHumiStatus.setText("未知");
            tvHumiStatus.setTextColor(Color.BLACK);
            rgbHumi.setProgressColor(Color.GREEN);

        }
        tvHumiMax.setText(humiMax + "% RH");
        tvHumiMin.setText(humiMin + "% RH");

        if (cGas > -100) {
            if (cGas > cGasMax) {
                tvCgas.setTextColor(Color.RED);
                tvCgasStatus.setText("异常");
                tvCgasStatus.setTextColor(Color.RED);
                rgbCgas.setProgressColor(Color.RED);
            } else {
                tvCgas.setTextColor(Color.GREEN);
                tvCgasStatus.setText("正常");
                tvCgasStatus.setTextColor(Color.GREEN);
            }
        } else {
            tvCgas.setTextColor(Color.BLACK);
            tvCgasStatus.setText("未知");
            tvCgasStatus.setTextColor(Color.BLACK);
            rgbCgas.setProgressColor(Color.GREEN);

        }

        tvCgasMax.setText(cGasMax + " ppm");

        tvCgasMin.setText(0 + " ppm");

        if (temp <= -100) {
            tvTemp.setText("未知");
            rgbTem.setProgressValue(0);
        } else {
            tvTemp.setText(temp + "℃");
            rgbTem.setProgressValue((int) temp);
        }
        if (humi <= -100) {
            tvHumi.setText("未知");
            rgbHumi.setProgressValue(0);
        } else {
            tvHumi.setText(humi + "% RH");
            rgbHumi.setProgressValue((int) humi);
        }
        if (cGas <= -100) {
            tvCgas.setText("未知");
            rgbCgas.setProgressValue(0);
        } else {
            tvCgas.setText(cGas + " ppm");
            rgbCgas.setProgressValue((int) cGas);
        }

    }


    @Override
    protected void onStop() {
        super.onStop();
        //解除订阅
//        if (singleKvStore != null) {
//            if(kvStoreObserverClient!=null){
//                singleKvStore.unSubscribe(kvStoreObserverClient);
//            }
//        }
    }
}


2. TVAbility

public class TVAbility extends Ability {

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setMainRoute(TVAbilitySlice.class.getName());
    //实现Ability的代码中显式声明需要使用多设备协同访问的权限
    requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC",}, 0);
  }
}

3. ability_tv.xml

<?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"
  ohos:background_element="$media:haibao">

  <Text
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:text="大棚数据监测"
    ohos:text_color="#ffffff"
    ohos:text_size="26vp"
    ohos:layout_alignment="center"
    ohos:top_margin="50vp"/>

  <DependentLayout
    ohos:height="match_parent"
    ohos:width="match_parent">

    <DirectionalLayout
      ohos:height="match_content"
      ohos:width="match_parent"
      ohos:left_padding="10vp"
      ohos:right_padding="10vp"
      ohos:center_in_parent="true"
      ohos:orientation="horizontal">
      <DirectionalLayout
        ohos:height="match_content"
        ohos:width="0"
        ohos:weight="1"
        ohos:layout_alignment="center"
        ohos:orientation="vertical">
        <Text
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:text="温度数据"
          ohos:text_size="20vp"
          ohos:padding="5vp"
          ohos:text_color="#ffffff"
          ohos:layout_alignment="center"/>
        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>
        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_content"
            ohos:orientation="vertical">
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最高温度阀值:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="当前温度:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最低温度阀值:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
          </DirectionalLayout>

          <DependentLayout
            ohos:height="100vp"
            ohos:width="100vp">
            <RoundProgressBar
              ohos:id="$+id:rgb_tem"
              ohos:height="match_parent"
              ohos:width="match_parent"
              ohos:progress_width="10vp"
              ohos:progress="0"
              ohos:max="100"
              ohos:start_angle="215"
              ohos:max_angle="290"
              ohos:progress_color="#00ff00"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMaxTemp"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text_color="#000000"
              ohos:align_parent_top="true"
              ohos:text="未知"
              ohos:top_margin="8vp"
              ohos:horizontal_center="true"/>
            <Text
              ohos:id="$+id:tvTemp"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text_color="#000000"
              ohos:text="未知"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMinTemp"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="14vp"
              ohos:text_color="#000000"
              ohos:text="未知"
              ohos:bottom_margin="8vp"
              ohos:align_parent_bottom="true"
              ohos:horizontal_center="true"/>
          </DependentLayout>

        </DirectionalLayout>


        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>
        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="温度状态:"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
          <Text
            ohos:id="$+id:tvTempStatus"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="未知"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
        </DirectionalLayout>
      </DirectionalLayout>


      <DirectionalLayout
        ohos:height="90vp"
        ohos:width="1vp"
        ohos:background_element="#000000"
        ohos:top_margin="6vp"
        ohos:layout_alignment="center"/>

      <DirectionalLayout
        ohos:height="match_content"
        ohos:width="0"
        ohos:weight="1"
        ohos:layout_alignment="center"
        ohos:orientation="vertical">
        <Text
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:text="湿度数据"
          ohos:text_size="20vp"
          ohos:padding="5vp"
          ohos:text_color="#ffffff"
          ohos:layout_alignment="center"/>
        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>


        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_content"
            ohos:orientation="vertical">
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最大湿度阀值:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="当前湿度:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最小湿度阀值:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
          </DirectionalLayout>

          <DependentLayout
            ohos:height="100vp"
            ohos:width="100vp">
            <RoundProgressBar
              ohos:id="$+id:rgb_humi"
              ohos:height="match_parent"
              ohos:width="match_parent"
              ohos:progress_width="10vp"
              ohos:progress="0"
              ohos:max="100"
              ohos:start_angle="215"
              ohos:max_angle="290"
              ohos:progress_color="#00ff00"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMaxHumi"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text_color="#000000"
              ohos:text="未知"
              ohos:top_margin="8vp"
              ohos:horizontal_center="true"
              ohos:align_parent_top="true"/>
            <Text
              ohos:id="$+id:tvHumi"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text_color="#000000"
              ohos:text="未知"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMinHumi"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text_color="#000000"
              ohos:horizontal_center="true"
              ohos:text="未知"
              ohos:bottom_margin="8vp"
              ohos:align_parent_bottom="true"/>
          </DependentLayout>

        </DirectionalLayout>

        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>
        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="湿度状态:"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
          <Text
            ohos:id="$+id:tvHumiStatus"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="未知"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
        </DirectionalLayout>

      </DirectionalLayout>



      <DirectionalLayout
        ohos:height="90vp"
        ohos:width="1vp"
        ohos:background_element="#000000"
        ohos:top_margin="6vp"
        ohos:layout_alignment="center"/>




      <DirectionalLayout
        ohos:height="match_content"
        ohos:width="0"
        ohos:weight="1"
        ohos:layout_alignment="center"
        ohos:orientation="vertical">
        <Text
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:text="CO2数据"
          ohos:text_size="20vp"
          ohos:padding="5vp"
          ohos:text_color="#ffffff"
          ohos:layout_alignment="center"/>
        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>
        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_content"
            ohos:orientation="vertical">
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最大气体增量:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="当前增量:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
            <Text
              ohos:height="0"
              ohos:width="match_content"
              ohos:text="最小气体增量:"
              ohos:text_size="16vp"
              ohos:weight="1"
              ohos:text_color="#000000"/>
          </DirectionalLayout>

          <DependentLayout
            ohos:height="100vp"
            ohos:width="100vp">
            <RoundProgressBar
              ohos:id="$+id:rgb_gas"
              ohos:height="match_parent"
              ohos:width="match_parent"
              ohos:progress_width="10vp"
              ohos:progress="0"
              ohos:max="1000"
              ohos:start_angle="215"
              ohos:max_angle="290"
              ohos:progress_color="#00ff00"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMaxCgas"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text="未知"
              ohos:text_color="#000000"
              ohos:top_margin="8vp"
              ohos:horizontal_center="true"
              ohos:align_parent_top="true"/>
            <Text
              ohos:id="$+id:tvCgas"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text="未知"
              ohos:text_color="#000000"
              ohos:center_in_parent="true"/>
            <Text
              ohos:id="$+id:tvMinCgas"
              ohos:height="match_content"
              ohos:width="match_content"
              ohos:text_size="15vp"
              ohos:text="未知"
              ohos:text_color="#000000"
              ohos:bottom_margin="8vp"
              ohos:horizontal_center="true"
              ohos:align_parent_bottom="true"/>
          </DependentLayout>
        </DirectionalLayout>

        <DirectionalLayout
          ohos:height="3vp"
          ohos:width="match_parent"
          ohos:background_element="#ffffff"
          ohos:top_margin="15vp"
          ohos:left_margin="20vp"
          ohos:right_margin="20vp"
          ohos:layout_alignment="center"
          ohos:bottom_margin="15vp"
          ohos:visibility="invisible"/>


        <DirectionalLayout
          ohos:height="match_content"
          ohos:width="match_content"
          ohos:layout_alignment="center"
          ohos:orientation="horizontal">
          <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="气体状态:"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
          <Text
            ohos:id="$+id:tvCgasStatus"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="未知"
            ohos:text_size="18vp"
            ohos:text_color="#000000"/>
        </DirectionalLayout>
      </DirectionalLayout>
    </DirectionalLayout>
  </DependentLayout>

</DirectionalLayout>

4.config.json

{
  "app": {
    "bundleName": "com.isoftstone. distributeddata ",
    "vendor": "isoftstone",
    "version": {
      "code": 1000000,
      "name": "1.0.0"
    }
  },
  "deviceConfig": {},
  "module": {
    "package": "com.isoftstone.distributeddata",
    "name": ".MyApplication",
    "mainAbility": "com.isoftstone.distributeddata.com.isoftstone.distributeddata.TVAbility",
    "deviceType": [
      "phone"
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry",
      "installationFree": false
    },
    "reqPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC"
      }
    ],
    "abilities": [
      {
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ],
        "orientation": "landscape",
        "name": "com.isoftstone.distributeddata.TVAbility",
        "icon": "$media:icon",
        "description": "$string:tvability_description",
        "label": "$string:entry_TVAbility",
        "type": "page",
        "launchType": "standard"
      }
    ],
    "metaData": {
      "customizeData": [
        {
          "name": "hwc-theme",
          "value": "androidhwext:style/Theme.Emui.NoTitleBar",
          "extra": ""
        }
      ]
    }
  }
}

更多原创内容请关注:软通动力HarmonyOS学院

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2021-12-13 11:34:53修改
11
收藏 9
回复
举报
8条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

厉害呀,有具体试点没有,想去参观一下。

1
回复
2021-12-13 14:14:21
软通田可辉
软通田可辉

大赛获奖项目!

回复
2021-12-13 16:57:03
Whyalone
Whyalone
棒!
回复
2021-12-13 18:23:16
鸿联
鸿联

感谢分享

回复
2021-12-13 20:53:14
Whyalone
Whyalone

感谢分享,就贼细节

回复
2021-12-17 15:46:57
软通动力HOS
软通动力HOS 回复了 Whyalone
感谢分享,就贼细节

那必须的!

回复
2021-12-17 16:56:44
Der_带鱼
Der_带鱼

感谢分享!!!

 

回复
2021-12-28 21:12:39
软通动力HOS
软通动力HOS 回复了 Der_带鱼
感谢分享!!!

谢谢支持

回复
2021-12-30 16:42:57
回复
    相关推荐