安卓综合编程实验【AS开发实验05】

在这里插入图片描述

项目已上传

前言

实验设备:yodo实验箱、笔记本电脑

要求:
1.读懂温湿度功能、继电器功能、光照度功能模块的代码
2.添加led灯控制、PWM调光控制模块代码
说明:
1.底层功能实现代码老师已给出,在MyApplication.java中
2. 将老师提供的串口通信所用文件jni和jnLibs复制到main文件下
3. 将老师提供的图片添加到mipmap文件夹中
4. 在build.graddle中添加代码

    externalNativeBuild{
        ndkBuild{
            path'src/main/jni/Android.mk'
        }
    }

报告

请添加图片描述
请添加图片描述
请添加图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

清单文件:AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.exp6_03195020">
    <uses-permission android:name="android.permission.INTERNET"/><!--添加网络权限-->
    <application
        android:name=".MyApplication" 
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"><!--app启动时关联MyApplication-->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

页面布局:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#a9a7a7"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@mipmap/tempback"
        android:gravity="center"
        android:text="服务端"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/tempback"
        android:orientation="horizontal">
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">
            <ImageView
                android:id="@+id/iv1"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:src="@mipmap/temp"/>
            <TextView
                android:id="@+id/temp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toEndOf="@+id/iv1"
                android:text="0℃"
                android:textColor="#de0909"
                android:textSize="20dp"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">
            <ImageView
                android:id="@+id/iv2"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:src="@mipmap/hehum"/>
            <TextView
                android:id="@+id/hehum"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toEndOf="@+id/iv2"
                android:text="0%"
                android:textColor="#de0909"
                android:textSize="20dp"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            >
            <ImageView
                android:id="@+id/iv3"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:src="@mipmap/guangzhao"/>
            <TextView
                android:id="@+id/guangzhao"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toEndOf="@+id/iv3"
                android:text="0Lux"
                android:textColor="#de0909"
                android:textSize="20dp"/>
        </RelativeLayout>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/tempback">
        <ImageView
            android:id="@+id/iv_jiadian"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_centerInParent="true"
            android:src="@mipmap/jidian"/>
        <Button
            android:id="@+id/bt1"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/iv_jiadian"
            android:onClick="kongzhi"/>
    </RelativeLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/tempback"
        android:orientation="horizontal">
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">
            <Button
                android:id="@+id/led_red"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:background="@mipmap/c_light_off" />
            <TextView
                android:id="@+id/text_red"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/led_red"
                android:layout_centerHorizontal="true"
                android:text="红灯"
                android:textColor="#DD001B"
                android:textSize="20sp" />
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">

            <Button
                android:id="@+id/led_white"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:background="@mipmap/c_light_off" />
            <TextView
                android:id="@+id/text_white"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/led_white"
                android:layout_centerHorizontal="true"
                android:text="白灯"
                android:textColor="#2EBCF4"
                android:textSize="20sp" />
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">

            <Button
                android:id="@+id/led_green"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:background="@mipmap/c_light_off" />
            <TextView
                android:id="@+id/text_green"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/led_green"
                android:layout_centerHorizontal="true"
                android:text="绿灯"
                android:textColor="#59A869"
                android:textSize="20sp" />
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">

            <Button
                android:id="@+id/led_yellow"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:background="@mipmap/c_light_off" />
            <TextView
                android:id="@+id/text_yellow"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/led_yellow"
                android:layout_centerHorizontal="true"
                android:text="黄灯"
                android:textColor="#FFE14D"
                android:textSize="20sp" />
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="120dp"
            android:layout_weight="1">
            <Button
                android:id="@+id/led_all"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:background="@mipmap/button_off" />
        </RelativeLayout>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@mipmap/tempback">
        <SeekBar
            android:id="@+id/seekBar"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="100"
            android:progress="0"/>
    </RelativeLayout>
</LinearLayout>

默认页面:MainActivity.java

package com.example.exp6_03195020;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android_serialport_api.SerialPort;
public class MainActivity extends AppCompatActivity {
    private MyApplication myApplication;//全局Application对象
    private SerialPort serialPort;//串口对象
    private InputStream inputStreamChuanKou;//串口输入流
    private OutputStream outputStreamChuanKou;//串口输出流
    private TextView wendu, shidu, guangzhaodu;//文本控件对象
    private Button bt1;//按钮控件对象
    private boolean jidianqi = true;//继电器开关布尔量
//================<<<<<        !!!(此注释标志为添加部分,以下再次出现不再解释)!!!
    //==============================添加功能1:led灯控制===============================
    private Button btred,btwhite,btgreen,btyellow,btall;//按钮控件对象
    private boolean redled = true;//红灯开关布尔量
    private boolean whiteled = true;//红灯开关布尔量
    private boolean greenled = true;//红灯开关布尔量
    private boolean yellowled = true;//红灯开关布尔量
    private boolean allled = true;//红灯开关布尔量
    //==============================添加功能2:调光灯控制====================================================
    private SeekBar seekBar;//拖动条控件对象
    private Context mContext;//上下文对象
    private byte[] cmd = {(byte) 0xCC, (byte) 0xEE, (byte) 0x01, (byte) 0x09, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF};//通信协议字节数组
//==================>>>>>
    //串口数据接收Handler
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {//重写handlerMessage方法
            byte[] data = msg.getData().getByteArray("data");//从消息中提取 data字段内容
            //接收到串口上传来的温湿度数据后进行判断
            if (data[3] == (byte) 0x03 && data[4] == (byte) 0x01) {//判断消息类型是否为温湿度
                byte byteXH = data[5];//获取温度高位数据
                byte byteXL = data[6];//获取温度低位数据
                byte byteYH = data[7];//获取湿度高位数据
                byte byteYL = data[8];//获取湿度高位数据
                wendu.setText("温度:" + String
                        .valueOf((byteXH * 256 + byteXL) / 100));//在文本框控件显示温度
                shidu.setText("湿度:" + String
                        .valueOf((byteYH * 256 + byteYL) / 100));//在文本框控件显示湿度
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {//重写Activity的onCreate函数,系统创建Activity时调用
        super.onCreate(savedInstanceState);//调用父类的onCreate
        setContentView(R.layout.activity_main);//为页面加载布局
        myApplication = (MyApplication) getApplication();//获取全局Application对象
        wendu = findViewById(R.id.temp);//获取温度文本框控件对象
        shidu = findViewById(R.id.hehum);//获取湿度文本控件对象
        guangzhaodu = findViewById(R.id.guangzhao);//获取光照度文本控件对象
        bt1 = findViewById(R.id.bt1);//获取按钮控件对象
//===============<<<<<
        init();//调用init函数,实现对led灯的控制
        mContext = this;//获取上下文对象
        PWM();//调用PWM函数,实现对调光灯的控制
//===============>>>>>>
        try {
            serialPort = myApplication.getSerialPort("/dev/ttyAMA5");//打开串口
            inputStreamChuanKou = serialPort.getInputStream();//获取串口输入流
            outputStreamChuanKou = serialPort.getOutputStream();//获取串口输出流
        } catch (IOException e) {//处理例外
            e.printStackTrace();
        }
        new Thread(new Runnable() {//创建串口接收进程
            @Override
            public void run() { //重写线程的 run方法
                byte[] date = new byte[16];//创建字节数组
                int len = -1;//定义长度变量
                try {
                    len = inputStreamChuanKou.read(date);
                    while (len != -1) {//循环读取串口的data数组
                        Message message = new Message();//创建消息对象
                        Bundle bundle = new Bundle();//创建数据包对象
                        bundle.putByteArray("data", date);//将data数据存入数据包的data字段
                        message.setData(bundle);//将数据包对象封装进消息
                        handler.sendMessage(message);//向串口接收Handler发送消息
                    }
                } catch (IOException e) {//处理IO例外
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (Exception e) {//处理其它例外
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();//开启串口接收线程
        myApplication.setOnConnectListener(new MyApplication.ConnectListener() {//设置myApplication的ConnectListener
            @Override
            public void onReceiveData(byte[] buffer) { //重写ConnectListener的onReceiveData函数,接收到 wifi socket 上的光照度数据
                if (buffer[3] == (byte) 0x02 && buffer[4] == (byte) 0x01) {//判断消息类型是否为光照度
                    byte byteXH = buffer[5];//获取光照度高位数据
                    byte byteXL = buffer[6];//获取光照度低位数据
                    guangzhaodu.setText("光照度:" + String.valueOf((byteXH * 256 + byteXL)));//在页面文本框控件上显示光照度
                }
            }
        });
    }
    public void kongzhi(View view) { //在串口上发送控制继电器指令
        if (jidianqi) {//继电器状态若为真,为关闭状态
            jidianqi = false;//先将继电器状态置为假
            bt1.setBackgroundResource(R.mipmap.on);//设置继电器图片控件背景-打开
            byte[] cmd_on = {(byte) 0xCC, (byte) 0xEE, (byte) 0x01, (byte) 0x18, (byte) 0x01,
                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF};//生成继电器开关质量协议消息
            try {
                outputStreamChuanKou.write(cmd_on);//在串口输入流上发送打开继电器指令
                outputStreamChuanKou.flush();//刷新串口输入流
            } catch (IOException e) {//处理IO例外
                e.printStackTrace();
            }
        } else {//继电器状态若为假,为打开状态
            jidianqi = true;//先将继电器状态置为真
            bt1.setBackgroundResource(R.mipmap.off);//设置继电器图片控件背景-关闭
            byte[] cmd_off = {(byte) 0xCC, (byte) 0xEE, (byte) 0x01, (byte) 0x18, (byte) 0x02,
                    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF};//生成继电器开关质量协议消息
            try {
                outputStreamChuanKou.write(cmd_off);//在串口输入流上发送关闭继电器指令
                outputStreamChuanKou.flush();//刷新串口输入流
            } catch (IOException e) {//处理IO例外
                e.printStackTrace();
            }
        }
    }
//=========================<<<<<
//===============================调光灯==================================
    private void PWM() { //控制调光灯
        seekBar = findViewById(R.id.seekBar);
        cmd[3] = (byte) 0x0A;
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //进度发生改变时会触发
                cmd[4] = (byte) Integer.parseInt(Integer.toHexString(progress/10),16);
                try {
                    outputStreamChuanKou.write(cmd);
                    outputStreamChuanKou.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                //按住SeekBar时会触发
                Toast.makeText(mContext,"正在调节亮度",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                //放开eekBar时会触发
                Toast.makeText(mContext,"停止调节亮度",Toast.LENGTH_SHORT).show();
            }
        });
    }
//===============================LED================================
    private void init()  {    //初始化led灯
        btred = findViewById(R.id.led_red);//获取红灯按钮对象
        btwhite = findViewById(R.id.led_white);//获取白灯按钮对象
        btgreen = findViewById(R.id.led_green);//获取绿灯按钮对象
        btyellow = findViewById(R.id.led_yellow);//获取黄灯按钮对象
        btall = findViewById(R.id.led_all);//获取全部灯按钮对象
        btred.setOnClickListener(new View.OnClickListener() {//设置红灯点击事件监听器
            @Override
            public void onClick(View v) {//重写onClick方法
                enlightred();//调用红灯控制函数enlightred
            }
        });
        btwhite.setOnClickListener(new View.OnClickListener() {//设置白灯点击事件监听器
            @Override
            public void onClick(View v) {//重写onClick方法
                enlightwhite();//调用白灯控制函数enlightred
            }
        });
        btgreen.setOnClickListener(new View.OnClickListener() {//设置绿灯点击事件监听器
            @Override
            public void onClick(View v) {//重写onClick方法
                enlightgreen();//调用绿灯控制函数enlightred
            }
        });
        btyellow.setOnClickListener(new View.OnClickListener() {//设置黄灯点击事件监听器
            @Override
            public void onClick(View v) {//重写onClick方法
                enlightyellow();//调用黄灯控制函数enlightred
            }
        });
        btall.setOnClickListener(new View.OnClickListener() {//设置全部灯点击事件监听器
            @Override
            public void onClick(View v) {//重写onClick方法
                enlightall();//调用全部灯控制函数enlightred
            }
        });
    }

    public void enlightred(){//红灯控制函数
        if (redled){//若红灯状态为真,为关闭状态
            redled = false;//先设置红灯状态为假
            cmd[3] = (byte) 0x09;//按通信协议修改指令
            cmd[4] = (byte) 0x01;
            btred.setBackgroundResource(R.mipmap.c_light_red);//设置红灯背景控件为打开图片
            myApplication.send(cmd);//调用myApplication的send方法发送指令
        }else {//若红灯状态为假,为打开状态
            redled = true;//先设置红灯状态为真
            cmd[3] = (byte) 0x09;//按通信协议修改指令
            cmd[4] = (byte) 0x02;
            btred.setBackgroundResource(R.mipmap.c_light_off);//设置红灯背景控件为关闭图片
            myApplication.send(cmd);//调用myApplication的send方法发送指令
        }
    }
    public void enlightwhite(){//白灯控制函数
        if (whiteled){
            whiteled = false;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x03;
            btwhite.setBackgroundResource(R.mipmap.c_light_white);
            myApplication.send(cmd);
        }else {
            whiteled = true;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x04;
            btwhite.setBackgroundResource(R.mipmap.c_light_off);
            myApplication.send(cmd);
        }
    }
    public void enlightgreen(){//绿灯控制函数
        if (greenled){
            greenled = false;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x05;
            btgreen.setBackgroundResource(R.mipmap.c_light_green);
            myApplication.send(cmd);
        }else {
            greenled = true;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x06;
            btgreen.setBackgroundResource(R.mipmap.c_light_off);
            myApplication.send(cmd);
        }
    }
    public void enlightyellow(){//黄灯控制函数
        if (yellowled){
            yellowled = false;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x07;
            btyellow.setBackgroundResource(R.mipmap.c_light_yellow);
            myApplication.send(cmd);
        }else {
            yellowled = true;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x08;
            btyellow.setBackgroundResource(R.mipmap.c_light_off);
            myApplication.send(cmd);
        }
    }
    public void enlightall(){//全部灯控制函数
        if (allled){
            allled = false;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x0c;
            btred.setBackgroundResource(R.mipmap.c_light_red);
            btwhite.setBackgroundResource(R.mipmap.c_light_white);
            btgreen.setBackgroundResource(R.mipmap.c_light_green);
            btyellow.setBackgroundResource(R.mipmap.c_light_yellow);
            btall.setBackgroundResource(R.mipmap.button_on);
            myApplication.send(cmd);
        }else {
            allled = true;
            cmd[3] = (byte) 0x09;
            cmd[4] = (byte) 0x0d;
            btred.setBackgroundResource(R.mipmap.c_light_off);
            btwhite.setBackgroundResource(R.mipmap.c_light_off);
            btgreen.setBackgroundResource(R.mipmap.c_light_off);
            btyellow.setBackgroundResource(R.mipmap.c_light_off);
            btall.setBackgroundResource(R.mipmap.button_off);
            myApplication.send(cmd);
        }
    }
//======================>>>>>
}

自定义Application类:MyApplication.java

package com.example.exp6_03195020;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import android_serialport_api.SerialPort;
public class MyApplication extends android.app.Application {//自定义Application类
    private Map<String, SerialPort> serialPortMap = new HashMap<String, SerialPort>(); //定义串口列表
    private static MyApplication instance;//创建MyApplication的实例对象
    //Application 的回掉方法
    public static final MyApplication getInstance() {//目前本项目未调用!!!
        return instance;
    }
    public SerialPort getSerialPort(String path) throws SecurityException, //打开并读取串口状态参数
            IOException, InvalidParameterException {
        return getSerialPort(path, 115200);///调用 getSerialPort(String path,int baudrate)
    }
    public SerialPort getSerialPort(String path, int baudrate) //打开串口并返回串口参数
            throws SecurityException, IOException, InvalidParameterException {
        System.out.println("MyApplication 启动");//输出串口启动信息
        SerialPort mSerialPort = serialPortMap.get(path);//按照路径从串口列表获取串口对象
        if (mSerialPort == null) {//如果读取结果为空
            /* Check parameters 检查参数 */
            if ((path.length() == 0) || (baudrate == -1)) {//检查串口路径参数是否错误
                throw new InvalidParameterException();
            }
            /* Open the serial port 打开串口 使用指定的端口名、波特率和奇偶校验位初始化 */
            mSerialPort = new SerialPort(new File(path), baudrate, 0);//创建新的串口对象
            serialPortMap.put(path, mSerialPort);//将串口对象插入串口列表
        }
        return mSerialPort;//返回串口对象
    }
    public void closeSerialPort() { //关闭串口,目前本项目未调用!!!
        for (SerialPort mSerialPort : serialPortMap.values()) {
            if (mSerialPort != null) {
                mSerialPort.close();
            }
        }
        serialPortMap.clear();
    }
    // --------------socket 通信--------
    private Socket socket = null;//创建Socket对象
    private ServerSocket serverSocket = null;//创建按ServerSocket对象
    public static OutputStream outputStream; //输出流
    private static ConnectListener mListener; // 接收接口类
    final LinkedList<Socket> list = new LinkedList<Socket>(); //socket 列表
    @Override
    public void onCreate() {//重写Application的OnCreate()函数,该函数被系统自动调用
        // TODO Auto-generated method stub
        super.onCreate();//调用父类的onCreate()
        //启动服务端
        ServerListeners listener1 = new ServerListeners(); //创建 socket 监听进程
        listener1.start(); //启动 socket 监听进程
    }
    //接口回调
    public interface ConnectListener { //接收接口类定义
        void onReceiveData(byte[] buffer); //接收数据函数在主程序 activity 中实现
    }
    public void setOnConnectListener(ConnectListener linstener) {//设置接收接口类
        this.mListener = linstener;
    } //设置接收接口类
    Handler mHandler = new Handler() { //接收 handler,处理socket接收到的数据
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 100://判断消息类型为100
                    if (mListener != null) {
                        mListener.onReceiveData(msg.getData().getByteArray("data"));//调用接收接口的onReceiveData字段内容
                    }
                    break;
            }
        }
    };
    /**
     * 处理 Socket 请求的线程类
     */
    class Task implements Runnable { //接收子线程

        private Socket socket;//创建socket对象
        /**
         * 构造函数
         */
        public Task(Socket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {//重写run方法
            while (true) {
                int size;//定义读取长度
                try {
                    InputStream inputStream = null; //定义输入流
                    inputStream = socket.getInputStream();//获取socket输入流
                    byte[] buffer = new byte[16];//定义接收字节数组
                    size = inputStream.read(buffer);//读取输入流到buffer,获取读取到数组的字节长度
                    if (size > 0) {//如果长度大于0
                        Message message = new Message();//创建消息对象
                        message.what = 100;//定义消息类型为100
                        Bundle bundle = new Bundle();//创建消息数据包
                        bundle.putByteArray("data", buffer);//将buffer数据放入消息包的data字段
                        message.setData(bundle);//将数据包封装进消息
                        mHandler.sendMessage(message);//向mHandler发送消息
                    }
                } catch (Exception e) {//处理例外
                    e.printStackTrace();
                    return;
                }
            }
        }
    }
    public class ServerListeners extends Thread { //socket 监听线程
        @Override
        public void run() {//重写run方法
            try {
                serverSocket = new ServerSocket(7777);//创建监听套接字,端口为7777
                while (true) {
                    System.out.println("等待客户端请求....");//输出“等待客户端请求...”
                    socket = serverSocket.accept();//接收对方连接请求,建立绘画套接字
                    System.out.println("收到请求,服务器建立连接...");//成功接收请求,输出提示消息
                    System.out.println("客户端" + socket.getInetAddress().getHostAddress() + "连接成功");//输出客户端地址消息
                    System.out.println("客户端" + socket.getRemoteSocketAddress() + "连接成功");//输出客户端地址信息
                    list.add(socket);//将会话套接字插入套接字列表
                    //每次都启动一个新的线程
                    new Thread(new Task(socket)).start(); //启动接收子线程
                }
            } catch (IOException e) {//处理例外
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    /**
     * 发送数据
     *
     * @param  bytes 需要发送的内容
     */
    public void send(byte[] bytes) { //Socket发送数据函数,供主程序调用
        System.out.println(list.size());//输出Socket列表长度
        for (Socket s : list) {//在列表里的所有Socket上发送消息
            System.out.println("客户端" + s.getInetAddress().getHostAddress());//输入客户端地址信息
            try {
                outputStream = s.getOutputStream();//获取输出流
                if (outputStream != null) {//如果输出流不为空
                    outputStream.write(bytes);//在输出流发送byte数据
                    outputStream.flush();//刷新输出流
                }
            } catch (IOException e) {//处理 io 例外
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {//处理其他例外
                System.out.println("客户端 socket 不存在。");
            }
        }
    }
    /**
     * 断开连接
     *
     * @throws IOException
     */
    public void disconnect() throws IOException {//关闭Socket连接函数,目前本项目未调用!!!
        System.out.println("客户端是否关闭 1");
        if (list.size() != 0) {
            for (Socket s : list) {
                s.close();
                System.out.println("客户端是否关闭 2");
            }
        }
        if (outputStream != null)
            outputStream.close();
        list.clear();
    }
}

附:通信协议

请添加图片描述
请添加图片描述
请添加图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
网络编程Android开发中非常重要的一部分,主要涉及到Socket通信、HTTP网络请求和Websocket等。下面是一个简单的Android网络编程实验实验目的:通过使用Socket通信实现Android客户端与服务器的通信。 实验步骤: 1.创建一个Android工程,并在MainActivity中布局一个EditText和一个Button。 2.在MainActivity中添加以下代码: ```java private EditText etContent; private Button btnSend; private Socket socket = null; private OutputStream outputStream = null; private InputStream inputStream = null; private String ip = "192.168.1.100";//服务器的IP地址 private int port = 8888;//服务器的端口 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etContent = findViewById(R.id.et_content); btnSend = findViewById(R.id.btn_send); btnSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String content = etContent.getText().toString(); new Thread(new Runnable() { @Override public void run() { try { if (socket == null) { socket = new Socket(ip, port); outputStream = socket.getOutputStream(); inputStream = socket.getInputStream(); } outputStream.write(content.getBytes()); outputStream.flush(); byte[] buffer = new byte[1024]; int len = inputStream.read(buffer); String result = new String(buffer, 0, len); Log.d("MainActivity", "result:" + result); } catch (IOException e) { e.printStackTrace(); } } }).start(); } }); } @Override protected void onDestroy() { super.onDestroy(); try { if (socket != null) { socket.close(); } if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } ``` 3.运行程序,在EditText中输入内容,点击Button发送数据,程序会将数据通过Socket通信发送到服务器,并接收服务器返回的数据。 注意事项: 1.需要在AndroidManifest.xml文件中添加网络权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> ``` 2.由于网络通信是耗时操作,所以需要在子线程中进行。 3.需要在程序退出时关闭Socket、输入流和输出流,以免造成资源浪费。 4.需要保证手机和服务器在同一局域网内,才能正常通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HAL9000pp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值