软件简介

结合一个控制实例,简要介绍一下安卓客户端软件。

主界面非常简洁,左边一个方向控制盘,和右边4个Button。方向盘是一个自定义的View,可以转动任意角度,程序里只响应4个方向,已经足够。四个Button分别对应相应的功能键。

 

通信实现原理

使用基于tcp协议的socket通信。串口WiFi模块配置成tcp Service模式,然后安卓连接串口wifi模块的热点,客户端作为tcp client 连接。连接成功后就可以相互发送数据。

 

具体实现

串口WiFi模块配置成tcp Service模式,IP设置为192.168.4.1,端口号3824。

(安卓需要先连接到串口WiFi模块所创建的热点。)

客户端的连接方式如下:

    private void Connect() {
        // 开启线程来发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    socket = new Socket();
                    socket.connect(new InetSocketAddress(HOST, PORT), 4000);
                    if(socket != null){
                        Message message = new Message();
                        message.what = CONNECTED_RESPONSE;
                        handler.sendMessage(message);
                    }
                }catch (IOException ex) {
                    ex.printStackTrace();
                    Message message = new Message();
                    message.what = RESPONSE_TIMEOUT;
                    handler.sendMessage(message);
                }
            }
        }).start();
    }

网络操作需要在非UI线程中进行。程序开启一个线程进行连接操作,连接结果通过一个Handler通知主线程,以便UI更新连接状态指示。

连接成功之后,就可以发送数据:

    private void TCPSend(final String data) {
        if(socket == null)
            return;
        // 开启线程来发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    PrintWriter writer = new PrintWriter(socket.getOutputStream());
                    writer.println(data);
                    writer.flush();
                }catch (IOException ex){
                    ex.printStackTrace();
                    Message message = new Message();
                    message.what = SEND_RESPONSE;
                    // 将服务器返回的结果存放到Message中
                    message.obj = "操作失败!";
                    handler.sendMessage(message);
                }
            }
        }).start();
    }

同样的,开启一个线程来进行网络操作,结果也是通过Handler通知主线程。

 

UI交互界面的响应

网络操作结果的响应通过一个Handler来完成:

    private Handler handler = new Handler() {
        // 在这里进行UI操作,将结果显示到界面上
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CONNECTED_RESPONSE:
                    bt_connect.setTextColor(Color.parseColor("#216F02"));
                    bt_connect.setText("已连接");
                    bt_connect.setClickable(false);
                    disconnect.setTextColor(Color.BLACK);
                    disconnect.setClickable(true);
                    break;
                case RESPONSE_TIMEOUT:
                    Toast.makeText(getApplicationContext(),"连接失败!", Toast.LENGTH_SHORT).show();
                case RECEIVER_RESPONSE:
                case SEND_RESPONSE:
                default:
                    break;
            }
        }
    };

如果连接成功,那么"连接"Button将变成灰色"已连接",且不可点击,"断开连接"将变成可点击,以表明当前是连接状态。

如果连接失败,就弹出一个Toast通知用户:

 

Button的点击响应如下:

   @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_connect:
                Connect();
                break;
            case R.id.button_disconnect:
                try {
                    socket.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
                socket = null;
                bt_connect.setTextColor(Color.BLACK);
                bt_connect.setText("连接");
                bt_connect.setClickable(true);
                disconnect.setTextColor(Color.GRAY);
                disconnect.setClickable(false);
                break;
            case R.id.button_auto:
                TCPSend("auto\r\n");
                btnAuto.setEnabled(false);
                btnDisAuto.setEnabled(true);
                break;
            case R.id.button_dis_auto:
                TCPSend("hand\r\n");
                btnDisAuto.setEnabled(false);
                btnAuto.setEnabled(true);
                break;
            default:
                break;
        }
    }

为防止重复的点击操作,在点击相应按钮后,根据当前状态,把相应的按钮设置成可点击或不可点击状态。

方向操纵杆的响应:

rockerViewLeft.setOnShakeListener(RockerView.DirectionMode.DIRECTION_4_ROTATE_45, new RockerView.OnShakeListener() {
                @Override
                public void onStart() {
                    mLogLeft.setText("停");
                }

                @Override
                public void direction(RockerView.Direction direction) {
                    String message = "";
                    switch (direction) {
                        case DIRECTION_LEFT:
                            message = "左转";
                            TCPSend("left\r\n");
                            break;
                        case DIRECTION_RIGHT:
                            message = "右转";
                            TCPSend("right\r\n");
                            break;
                        case DIRECTION_UP:
                            message = "前进";
                            TCPSend("forward\r\n");
                            break;
                        case DIRECTION_DOWN:
                            message = "后退";
                            TCPSend("back\r\n");
                            break;
                        case DIRECTION_CENTER:
                        default:
                            break;
                    }
                    mLogLeft.setText(message);
                }
                @Override
                public void onFinish() {
                    mLogLeft.setText("停");
                    TCPSend("stop\r\n");
                }
            });

操纵杆红点会跟随触摸位置而改变,上方有相应的状态指示,并且松手后会自动滑回中间的停止状态。

 

END

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐