[作品] 12“万里”树莓派小车——socket学习(Android收发)

lb8820265   2021-11-29 20:14 楼主

前面介绍了Android使用UDP协议发送的代码,但要实现接收的功能却是比较复杂了,这里直接用前人写好的库事半功倍。

在GitHub上找到一个UDP的封装,详见文章末尾的源码。

APP搭建步骤

    新建一个空白工程,在AndroidManifest.xml中添加网络使用权限,和上篇一样。

    将UdpClient.java文件复制到和MainActivity.java同一个文件夹内。不要直接在文件夹内复制,在Android Studio上复制,会自动修改包名。

image-20211129012013-1.png  修改布局文件“activity_main.xml”,布局比较复杂,可看最后的效果图

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接状态:"/>
            <TextView
                android:id="@+id/tv_state"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:text="未连接"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="服务器IP地址:"/>
            <EditText
                android:id="@+id/et_ip"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:text="192.168.31.34"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="服务器端口号:"/>
            <EditText
                android:id="@+id/et_port"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:text="1234"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <Button
                android:id="@+id/btn_connect"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接"
                android:onClick="onClick"
                android:layout_weight="1"/>
            <Button
                android:id="@+id/btn_disconnect"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="断开"
                android:onClick="onClick"
                android:layout_weight="1"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送内容:"/>
            <EditText
                android:id="@+id/et_send"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:text="lb8820265"/>
        </LinearLayout>
        <Button
            android:id="@+id/btn_send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="onClick"
            android:text="发送"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="接收内容:"/>
            <Button
                android:id="@+id/btn_clear"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:onClick="onClick"
                android:text="清空接收"/>
        </LinearLayout>
        <ScrollView
            android:id="@+id/sv_receive"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
                 <EditText
                    android:id="@+id/et_receive"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:textColor="@color/black"
                     android:background="@null"/>
        </ScrollView>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

编写MainActivity.java函数,主要就是初始化监听,编写各个控件的相应函数。

package com.example.lb_socket_android;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
    private EditText et_ip;
    private EditText et_port;
    private EditText et_send;
    private EditText et_receive;
    private TextView tv_state;
    private ScrollView sv_receive;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_ip= (EditText) findViewById (R.id.et_ip);
        et_port= (EditText) findViewById (R.id.et_port);
        et_send=(EditText) findViewById (R.id.et_send);
        tv_state= (TextView) findViewById (R.id.tv_state);
        et_receive= (EditText) findViewById (R.id.et_receive);
        sv_receive= (ScrollView) findViewById (R.id.sv_receive);
        UdpClient.getInstance().setOnDataReceiveListener(dataReceiveListener);
    }
    public void onClick(View view){
        switch (view.getId()) {
            case R.id.btn_clear:
                et_receive.setText("");
                break;
            case R.id.btn_send:
                if (UdpClient.getInstance().isConnect()) {
                    byte[] data=et_send.getText().toString().getBytes();
                    String str = new String(data);
                    Log.i("TAG_log",str);
                    UdpClient.getInstance().sendByteCmd(data,1001);
                } else {
                    Toast.makeText(MainActivity.this,"尚未连接,请连接Socket",Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.btn_connect:
                String ip = et_ip.getText().toString();
                String port = et_port.getText().toString();

                if(TextUtils.isEmpty(ip)){
                    Toast.makeText(MainActivity.this,"IP地址为空",Toast.LENGTH_SHORT).show();
                    return;
                }
                if(TextUtils.isEmpty(port)){
                    Toast.makeText(MainActivity.this,"端口号为空",Toast.LENGTH_SHORT).show();
                    return;
                }
                UdpClient.getInstance().connect(ip, Integer.parseInt(port));
                break;
            case R.id.btn_disconnect:
                UdpClient.getInstance().disconnect();
                tv_state.setText("未连接");
                break;
            default:
                break;
        }
    }
    private UdpClient.OnDataReceiveListener dataReceiveListener = new UdpClient.OnDataReceiveListener() {
        @Override
        public void onConnectSuccess() {
            Log.i("TAG_log","onDataReceive connect success");
            tv_state.setText("已连接");
        }
        @Override
        public void onConnectFail() {
            Log.e("TAG_log","onDataReceive connect fail");
            tv_state.setText("未连接");
        }
        @Override
        public void onDataReceive(byte[] buffer, int size, int requestCode) {
            //获取有效长度的数据
            byte[] data = new byte[size];
            System.arraycopy(buffer, 0, data, 0, size);
            String oxValue = new String(data);
            Log.i("TAG_log","onDataReceive requestCode = "+requestCode + ", content = "+oxValue);
            et_receive.append(oxValue + "\n");
            sv_receive.fullScroll(View.FOCUS_DOWN);
        }
    };
    @Override
    protected void onDestroy() {
        UdpClient.getInstance().disconnect();
        super.onDestroy();
    }
}

运行方法

  1. 手机和PC连在同一个路由器上,获取PC的IP地址,并修改APP代码中的IP地址。
  2. 在Windows上编译并运行之前写的socket_UDP_win_server.cpp。
  3. 编译并在实机上运行APP,先点击“连接”,然后点击“发送”按钮。

运行效果

image-20211129012013-2.png

问题

通信的问题解决了,那么接下来就是面向小车编程了,如何控制电机,如何控制速度等。

源码

    GitHub:https://github.com/wanli-car/Examples/tree/master/Android/lb_socket_Android

    Gitee:https://gitee.com/wanli-car/Examples/tree/master/Android/lb_socket_Android

QQ:252669569

回复评论 (5)

1 来自 2楼 okhxyyo 

"万里"树莓派小车汇总贴:

lb8820265的“万里”树莓派小车开源分享 - DIY/开源硬件专区 - 电子工程世界-论坛 (eeworld.com.cn)

 

目录:

 

“万里”树莓派小车开张贴 

1“万里”树莓派小车——建立项目仓库

2“万里”树莓派小车——python学习(Thonny的使用)

3“万里”树莓派小车——python学习(定时任务)

4“万里”树莓派小车——C++学习(编译与运行,geany使用)

5“万里”树莓派小车——wiringPi学习(延时与线程模拟定时器)

6“万里”树莓派小车——wiringPi学习(PWM与外部中断模拟定时器)

7“万里”树莓派小车——RPi.GPIO学习(PWM与外部中断模拟定时器)

8“万里”树莓派小车——socket学习(本机通讯)

9“万里”树莓派小车——socket学习(TCP两机通讯)

10“万里”树莓派小车——socket学习(UDP两机通讯)

11“万里”树莓派小车——socket学习(Android发送)

12“万里”树莓派小车——socket学习(Android收发)

13“万里”树莓派小车——配件准备

14“万里”树莓派小车——电机驱动学习

15“万里”树莓派小车——光电编码器学习(正反转的判断)

16“万里”树莓派小车——光电编码器学习(转速的获取)

17“万里”树莓派小车——VSCode学习(编译和调试)

18“万里”树莓派小车——Makefile学习

19“万里”树莓派小车——VSCode学习(多C文件链接调试)

20“万里”树莓派小车——电机控制学习(控制速度)

21“万里”树莓派小车——电机控制学习(4轮速度控制)
22“万里”树莓派小车——手机遥控电机转动

23“万里”树莓派小车——无屏幕连接树莓派

24“万里”树莓派小车——树莓派64位系统bullseye跑分测试

25“万里”树莓派小车——纳姆轮控制

26“万里”树莓派小车——程序开机启动

27“万里”树莓派小车——固定和获取树莓派IP地址

28“万里”树莓派小车——小车组装

29“万里”树莓派小车——直行偏向问题与新控制模式

30.“万里”树莓派小车——第一阶段完成展示(从零开始介绍)

玩板看这里: https://bbs.eeworld.com.cn/elecplay.html EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
点赞  2022-3-21 13:40

666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666

点赞  2021-11-30 04:40

加油,进展显著。

加油!在电子行业默默贡献自己的力量!:)
点赞  2021-11-30 11:10

学习了

点赞  2021-12-1 08:36
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复