基于HarmonyOS控制Hi3861小車之信息通信
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
引言
在鴻蒙應(yīng)用實際開發(fā)中,經(jīng)常會遇到App與IOT設(shè)備間的通信,本節(jié)主要詳細(xì)講述一下通信關(guān)鍵技術(shù),考慮到TCP/UDP協(xié)議的特性,兩者間通過UDP進(jìn)行通信是一種必然的選擇,UDP一種無連接的協(xié)議,具有資源消耗小,處理速度快的優(yōu)點,了解UDP是怎么通信的,這對于每一個HarmonyOS開發(fā)者也是需要了解的重點知識。
核心類
DatagramSocket、DatagramPacket、EventHandler,下面分別簡單介紹下:
1.DatagramSocket:
構(gòu)造器DatagramSocket(int port, InetAddress laddr):創(chuàng)建一個DatagramSocket實例,并將該對象綁定到指定IP地址、指定端口。主要方法receive(DatagramPacket p):從該DatagramSocket中接收數(shù)據(jù)報,send(DatagramPacket p):以該DatagramSocket對象向外發(fā)送數(shù)據(jù)報。
2.DatagramPacket:
構(gòu)造器DatagramPacket(byte[] buf, int length, InetAddress addr, int port):以一個包含數(shù)據(jù)的數(shù)組來創(chuàng)建DatagramPacket對象,創(chuàng)建該DatagramPacket對象時還指定了IP地址和端口--這就決定了該數(shù)據(jù)報的目的地。
3.EventHandler:
是HarmonyOS用于處理線程間通信的一種機(jī)制,可以通過EventRunner創(chuàng)建新線程,將耗時的操作放到新線程上執(zhí)行。這樣既不阻塞原來的線程,任務(wù)又可以得到合理的處理。比如:主線程使用EventHandler創(chuàng)建子線程,子線程做耗時的下載圖片操作,下載完成后,子線程通過EventHandler通知主線程,主線程再更新UI。
功能介紹
通過App Demo控制小車運(yùn)動(前進(jìn)、后退、左轉(zhuǎn)、右轉(zhuǎn)、停止),主要通過UDP數(shù)據(jù)包發(fā)送命令,來說明它們間是怎么通信的,它們間控制命令以json格式發(fā)送。
如:
- "mode": "CarControl",//控制命令分類
- "cmd": "forward"//具體命令
- }。
開發(fā)指南
1、創(chuàng)建UDP協(xié)議的發(fā)送命令對象
- private UdpManager() {
- try {
- mGpsDatagramSocket = new DatagramSocket();
- } catch (SocketException e) {
- e.printStackTrace();
- }
- }
2、將要發(fā)送的數(shù)據(jù)封裝成DatagramPacket對象發(fā)送
- DatagramPacket sRequest = new DatagramPacket(mInfoArray, mInfoArray.length,
- InetAddress.getByName(getIp()), PORT);
- // 開始發(fā)送
- mGpsDatagramSocket.send(sRequest);
3、構(gòu)造發(fā)送的命令
- public void sendMessage(String info) {
- Gson gson = new Gson();
- WifiCommand messageInfo = new WifiCommand();
- messageInfo.setCmd(info);
- //控制類型
- messageInfo.setMode();
- //轉(zhuǎn)換成json
- String resultJson = gson.toJson(messageInfo);
- // 創(chuàng)建發(fā)送命令SendMessageRunnable對象
- mSendMessageRunnable = new SendMessageRunnable();
- mSendMessageRunnable.setInfoArray(resultJson.getBytes(StandardCharsets.UTF_8));
- // 啟動發(fā)送命令線程
- mEventHandler.postTask(mSendMessageRunnable);
- if ("stop".equals(info) || "tripod_on".equals(info) || "tripod_off".equals(info)){
- HiLog.info(label, "info = " + info);
- } else {
- // 啟動發(fā)送Gps請求線程和接收信息線程
- startReceive();
- startSendGpsMessage();
- }
- HiLog.info(label, "sendMessage = " + resultJson);
- }
實現(xiàn)效果

附上主要源代碼
1. MainAbilitySlice
- public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener{
- private Button iTurnUp,iTurnDown,iTurnLeft,iTurnRight,iTurnRun;
- private UdpManager udpManager;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_main);
- initComponent();
- // 初始化WiFi控制對象
- udpManager = UdpManager.getInstance(this);
- }
- private void initComponent(){
- iTurnUp = (Button) findComponentById(ResourceTable.Id_i_up);
- iTurnUp.setClickedListener(this);
- iTurnDown = (Button) findComponentById(ResourceTable.Id_i_down);
- iTurnDown.setClickedListener(this);
- iTurnLeft = (Button) findComponentById(ResourceTable.Id_i_left);
- iTurnLeft.setClickedListener(this);
- iTurnRight = (Button) findComponentById(ResourceTable.Id_i_right);
- iTurnRight.setClickedListener(this);
- iTurnRun = (Button) findComponentById(ResourceTable.Id_i_run);
- iTurnRun.setClickedListener(this);
2. UdpManager
- /**
- * UDP連接類
- */
- public class UdpManager {
- private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00134, "UdpManager");
- private static final int PORT = 48100;
- private static final int GET_MESSAGE = 1;
- private static UdpManager sUdpManager;
- private static Context sContext;
- private UdpReceiveCallback mReceiveInformationCallback;
- private ReceiveMessageRunnable mReceiveMessageRunnable;
- private SendGpsMessageRunnable mSendGpsMessageRunnable;
- private SendMessageRunnable mSendMessageRunnable;
- private DatagramSocket mGpsDatagramSocket;
- private static String ip = "192.168.0.1";
- /**
- * 控制是否還需要接收信息控制器
- */
- private boolean flag = false;
- private final EventHandler mEventHandler = new EventHandler(EventRunner.create()) {
- @Override
- protected void processEvent(InnerEvent event) {
- super.processEvent(event);
- if (event.eventId == GET_MESSAGE) {
- if (mReceiveInformationCallback != null) {
- mReceiveInformationCallback.getMessage(event.object);
- }
- }
- }
- };
- private final EventHandler mReceiveEventHandler = new EventHandler(EventRunner.create()) {
- };
- private final EventHandler mSendGpsEventHandler = new EventHandler(EventRunner.create()) {
- };
- /**
- * UdpManager的單例
- *
- * @return UdpManager單例對象
- */
- public static UdpManager getInstance(Context context) {
- if (sUdpManager == null) {
- sUdpManager = new UdpManager();
- sContext = context;
- }
- return sUdpManager;
- }
- /**
- * 構(gòu)造函數(shù)
- */
- private UdpManager() {
- // 創(chuàng)建UDP協(xié)議的發(fā)送命令對象
- try {
- mGpsDatagramSocket = new DatagramSocket();
- } catch (SocketException e) {
- e.printStackTrace();
- }
- }
- /**
- * 注冊接收信息的回調(diào)函數(shù)
- *
- * @param callback 接收信息回調(diào)函數(shù)
- */
- public void registerCallback(UdpReceiveCallback callback) {
- mReceiveInformationCallback = callback;
- }
- /**
- * 對外提供的發(fā)送命令方法
- *
- * @param info 需要發(fā)送的命令
- */
- public void sendMessage(String info) {
- Gson gson = new Gson();
- UdpCommand messageInfo = new UdpCommand();
- // 傳進(jìn)來的控制命令
- messageInfo.setCmd(info);
- //控制類型
- messageInfo.setMode();
- //轉(zhuǎn)換成json
- String resultJson = gson.toJson(messageInfo);
- // 創(chuàng)建發(fā)送命令SendMessageRunnable對象
- mSendMessageRunnable = new SendMessageRunnable();
- mSendMessageRunnable.setInfoArray(resultJson.getBytes(StandardCharsets.UTF_8));
- // 啟動發(fā)送命令線程
- mEventHandler.postTask(mSendMessageRunnable);
- // 啟動發(fā)送Gps請求線程和接收信息線程
- if ("stop".equals(info)) {
- HiLog.info(label, "info = " + info);
- } else {
- // 啟動發(fā)送Gps請求線程和接收信息線程
- startReceive();
- startSendGpsMessage();
- }
- HiLog.info(label, "sendMessage = " + resultJson);
- }
- public String getIp() {
- return ip;
- }
- public void setIp(String mIp) {
- this.ip = mIp;
- }
- /**
- * 內(nèi)部類,用作發(fā)送命令
- */
- private class SendMessageRunnable implements Runnable {
- private byte[] mInfoArray;
- void setInfoArray(byte[] infoArray) {
- mInfoArray = infoArray;
- }
- @Override
- public void run() {
- HiLog.info(label, "發(fā)送線程 = " + Thread.currentThread().getName());
- // 發(fā)送數(shù)據(jù)
- try {
- // 延時發(fā)送50毫秒,因為如果不延時會將小車卡死
- Thread.sleep(50);
- // 將要發(fā)送的數(shù)據(jù)封裝成DatagramPacket對象
- DatagramPacket sRequest = new DatagramPacket(mInfoArray, mInfoArray.length,
- InetAddress.getByName(getIp()), PORT);
- // 開始發(fā)送
- mGpsDatagramSocket.send(sRequest);
- } catch (IOException | InterruptedException e) {
- e.printStackTrace();
- HiLog.info(label, "sendMessage error");
- }
- }
- }
- /**
- * 內(nèi)部類,用作接收命令
- */
- private class ReceiveMessageRunnable implements Runnable {
- @Override
- public void run() {
- try {
- while (flag) {
- byte[] buf = new byte[1024];
- DatagramPacket receiveDatagramPacket = new DatagramPacket(buf, buf.length);
- if (mGpsDatagramSocket != null && !mGpsDatagramSocket.isClosed()) {
- HiLog.info(label, "接收線程開始阻塞" + Thread.currentThread().getName());
- // 接收返回數(shù)據(jù),會阻塞線程
- mGpsDatagramSocket.receive(receiveDatagramPacket);
- // 將得到的數(shù)據(jù)轉(zhuǎn)成json
- String json = new String(receiveDatagramPacket.getData(), StandardCharsets.UTF_8);
- json = json.substring(json.indexOf("{"), json.lastIndexOf("}")+1);
- HiLog.info(label, "receiveMessage json = " + json);
- // 將對象發(fā)送給需要接收返回值的地方
- mEventHandler.sendEvent(InnerEvent.get(GET_MESSAGE, json));
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- HiLog.error(label, "receiveMessage error");
- }
- }
- }
- /**
- * 內(nèi)部類,用作發(fā)送請求Gps命令
- */
- private class SendGpsMessageRunnable implements Runnable {
- @Override
- public void run() {
- Gson gson = new Gson();
- UdpCommand messageInfo = new UdpCommand();
- // 傳進(jìn)來的控制命令
- messageInfo.setCmd("getinfo");
- //控制類型
- messageInfo.setMode();
- //轉(zhuǎn)換成json
- String resultJson = gson.toJson(messageInfo);
- byte[] infoArray = resultJson.getBytes(StandardCharsets.UTF_8);
- try {
- // 將要發(fā)送的數(shù)據(jù)封裝成DatagramPacket對象
- DatagramPacket sRequest = new DatagramPacket(infoArray, infoArray.length,
- InetAddress.getByName(getIp()), PORT);
- // 開始發(fā)送
- mGpsDatagramSocket.send(sRequest);
- // 啟動獲取Gps命令線程
- mSendGpsEventHandler.postTask(mSendGpsMessageRunnable, 2000);
- HiLog.info(label, "發(fā)送gps");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 啟動接收消息
- */
- private void startReceive() {
- if (!flag) {
- flag = true;
- // 創(chuàng)建接收命令ReceiveMessageRunnable對象
- mReceiveMessageRunnable = new ReceiveMessageRunnable();
- // 啟動接收命令線程
- mReceiveEventHandler.postTask(mReceiveMessageRunnable);
- HiLog.info(label, "開啟接收線程");
- }
- }
- /**
- * 開始獲取gps點
- */
- private void startSendGpsMessage() {
- // 創(chuàng)建發(fā)送Gps命令SendGpsMessageRunnable對象
- if (mSendGpsMessageRunnable == null) {
- mSendGpsMessageRunnable = new SendGpsMessageRunnable();
- }
- // 啟動獲取Gps命令線程
- mSendGpsEventHandler.postTask(mSendGpsMessageRunnable);
- HiLog.info(label, "開啟發(fā)送gps請求線程");
- }
3. UdpCommand
- class UdpCommand {
- // 控制命令:forward,back,left,right
- private String cmd;
- // 控制類型
- private String mode;
- public String getCmd() {
- return cmd;
- }
- void setCmd(String cmd) {
- this.cmd = cmd;
- }
- public String getMode() {
- return mode;
- }
- void setMode() {
- this.mode = "CarControl";
- }
- }
4. UdpReceiveCallback
- /**
- * 接收小車返回數(shù)據(jù)的回調(diào)函數(shù)
- */
- public interface UdpReceiveCallback {
- void getMessage(Object value);
- }
5. 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:alignment="center"
- ohos:orientation="vertical">
- <DirectionalLayout
- ohos:height="70vp"
- ohos:width="match_parent"
- ohos:orientation="horizontal"
- ohos:layout_alignment="center"
- ohos:top_margin="10vp" >
- <Button
- ohos:id="$+id:i_up"
- ohos:height="50vp"
- ohos:width="120vp"
- ohos:background_element="#FF9F9F9F"
- ohos:left_margin="60vp"
- ohos:text_size="25fp"
- ohos:text="前進(jìn)"/>
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)