Android 蓝牙串口通讯Demo

计算机软件开发 2024-9-21 10:16:12 43 0 来自 中国
关于怎样设置条记本电脑的蓝牙 串口而且和手机蓝牙配对,以及pc串口调试工具的下载请看这篇博客:
https://blog.csdn.net/weixin_44902943/article/details/113114481
通过上面这篇博客的利用再进入app就能实现本Demo 和 pc串口调试工具的数据互传了。(如果在app中总是表现毗连堕落,多半是由于蓝牙没有配对好,关闭蓝牙再多配对反复)
结果图
先点击开启蓝牙(纵然蓝牙已打开),然后再搜索装备,列表里没有找到继承点击搜索装备
点击要毗连的装备跳转到通讯页面



源码(带表明)

发起先认识一下蓝牙开发的相干api再来看。
1、布局代码

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">    <Button        android:id="@+id/open_bluetooth_btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="开启蓝牙"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintHorizontal_bias="0.27"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintVertical_bias="0.07" />    <Button        android:id="@+id/fount_device_btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="搜索装备"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintHorizontal_bias="0.694"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintVertical_bias="0.07" />    <TextView        android:id="@+id/textView"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginStart="10dp"        android:layout_marginTop="20dp"        android:text="蓝牙装备列表"        android:textColor="@color/black"        android:textSize="16sp"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintHorizontal_bias="0.0"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toBottomOf="@+id/open_bluetooth_btn"        app:layout_constraintVertical_bias="0.0" />    <ListView        android:id="@+id/bluetooth_device_list"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="10dp"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toBottomOf="@+id/textView"        app:layout_constraintVertical_bias="0.0" /></androidx.constraintlayout.widget.ConstraintLayout>communication_layout.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">    <Button        android:id="@+id/send_text_btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginEnd="10dp"        android:layout_marginBottom="10dp"        android:text="发送"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintHorizontal_bias="1.0"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintVertical_bias="1.0" />    <EditText        android:id="@+id/send_edit_text"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_marginStart="10dp"        android:layout_marginEnd="4dp"        android:layout_marginBottom="10dp"        android:hint="输入要发送的信息"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintEnd_toStartOf="@+id/send_text_btn"        app:layout_constraintHorizontal_bias="0.0"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintVertical_bias="1.0" />    <TextView        android:id="@+id/bluetooth_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="蓝牙装备名称"        android:textColor="@color/black"        android:textSize="18sp"        app:layout_constraintBottom_toTopOf="@+id/send_edit_text"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintVertical_bias="0.0" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="0dp"        androidrientation="horizontal"        android:padding="10dp"        app:layout_constraintBottom_toTopOf="@+id/send_edit_text"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toBottomOf="@+id/bluetooth_name">        <TextView            android:id="@+id/received_text_content"            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_marginRight="5dp"            android:layout_weight="1"            android:background="@drawable/communication_list_shape"            android:padding="4dp"            android:text="我收到的信息:"            android:textColor="@color/black" />        <TextView            android:id="@+id/send_text_content"            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_marginLeft="5dp"            android:layout_weight="1"            android:background="@drawable/communication_list_shape"            android:padding="4dp"            android:text="我发出的信息:"            android:textColor="@color/black" />    </LinearLayout>    <TextView        android:id="@+id/cancel_conn_btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginStart="10dp"        android:text="竣事"        android:textColor="@color/purple_500"        android:textSize="16sp"        app:layout_constraintBottom_toBottomOf="@+id/bluetooth_name"        app:layout_constraintEnd_toStartOf="@+id/bluetooth_name"        app:layout_constraintHorizontal_bias="0.0"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>2、Java代码

MainActivity.java
package com.example.bluetoothdemo;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import android.Manifest;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.pm.PackageManager;import android.os.Build;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.Button;import android.widget.ListView;import com.example.bluetoothdemo.adapter.MyArrayAdapter;import com.example.bluetoothdemo.bean.DeviceInformation;import com.example.bluetoothdemo.utils.ToastUtil;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.List;import java.util.UUID;public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private static final int MY_PERMISSION_REQUEST_CONSTANT = 1;    private Button mOpenBluetoothBtn;    private Button mFoundDeviceBtn;    private ListView mDeviceList;    private MyArrayAdapter mAdapter;    private List<DeviceInformation> mDatas = new ArrayList<>();    private BluetoothAdapter mBluetoothAdapter;    private ToastUtil mToast;    private BroadcastReceiver mBluetoothReceiver;//用于吸收蓝牙状态改变广播的广播吸收者    private String TAG = "MainActivity";    private BroadcastReceiver mBLuetoothStateReceiver;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initReceiver();        initView();        initListener();    }    /*    注册广播吸收者     */    private void initReceiver() {        //创建用于吸收蓝牙状态改变广播的广播吸收者        mBLuetoothStateReceiver = new BroadcastReceiver(){            @Override            public void onReceive(Context context, Intent intent) {                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);                switch (state){                    case BluetoothAdapter.STATE_ON:                        mToast.showToast("蓝牙已打开");                        break;                    case BluetoothAdapter.STATE_OFF:                        mToast.showToast("蓝牙已关闭");                        break;                    case BluetoothAdapter.STATE_TURNING_ON:                        mToast.showToast("蓝牙正在打开");                        break;                    case BluetoothAdapter.STATE_TURNING_OFF:                        mToast.showToast("蓝牙正在关闭");                        break;                }            }        };        //创建装备扫描广播吸收者        mBluetoothReceiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                Log.d(TAG,"onReceive");                String action = intent.getAction();                if (BluetoothDevice.ACTION_FOUND.equals(action)) {                    boolean isAdded = false;//标志扫描到的装备是否已经在数据列表里了                    //获取扫描到的装备                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);                    //生存装备的信息                    DeviceInformation deviceInformation = new DeviceInformation(device.getName(),device.getAddress());                    for (DeviceInformation data : mDatas) {                        //判断已生存的装备信息里是否有一样的                        if (data.getDeviceAddress().equals(deviceInformation.getDeviceAddress())) {                            isAdded = true;                            break;                        }                    }                    if (!isAdded) {                        //关照UI更新                        mDatas.add(deviceInformation);                        mAdapter.notifyDataSetChanged();                    }                }            }        };        //注册广播吸收者        IntentFilter filter1 = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);        IntentFilter filter2 = new IntentFilter(BluetoothDevice.ACTION_FOUND);        registerReceiver(mBLuetoothStateReceiver,filter1);        registerReceiver(mBluetoothReceiver,filter2);    }    //权限是否授予,给出提示    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {        switch (requestCode) {            case MY_PERMISSION_REQUEST_CONSTANT: {                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    mToast.showToast("权限授权乐成");                }else{                    mToast.showToast("权限授权失败");                }                return;            }        }    }    private void initView() {        //安卓6.0开始须要动态申请权限        if (Build.VERSION.SDK_INT >= 6.0) {            ActivityCompat.requestPermissions(this, new String[]{                            Manifest.permission.ACCESS_FINE_LOCATION},                    MY_PERMISSION_REQUEST_CONSTANT);        }        mOpenBluetoothBtn = findViewById(R.id.open_bluetooth_btn);        mFoundDeviceBtn = findViewById(R.id.fount_device_btn);        mDeviceList = findViewById(R.id.bluetooth_device_list);        mToast = new ToastUtil(this);        mAdapter = new MyArrayAdapter(mDatas,this);        mDeviceList.setAdapter(mAdapter);    }    //初始化监听    private void initListener() {        mOpenBluetoothBtn.setOnClickListener(this);        mFoundDeviceBtn.setOnClickListener(this);        //装备列表item的点击变乱        mDeviceList.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {                if (mBluetoothAdapter.isDiscovering()) {                    //克制搜索装备                    mBluetoothAdapter.cancelDiscovery();                }                //获取点击的item的装备信息                DeviceInformation deviceInformation = mDatas.get(position);                //跳转到装备通讯页面                Intent intent = new Intent(MainActivity.this,CommunicationActivity.class);                //将装备地点通报已往                intent.putExtra("name",deviceInformation.getDeviceName());                intent.putExtra("address",deviceInformation.getDeviceAddress());                startActivity(intent);            }        });    }    /**     * 检测和开启蓝牙     */    private void openBluetooth() {        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();        if (mBluetoothAdapter != null) {            //判断蓝牙是否打开并可见            if (!mBluetoothAdapter.isEnabled()) {                //哀求打开并可见                Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);                startActivityForResult(intent,1);            }        }else{            mToast.showToast("装备不支持蓝牙功能");        }    }    /**     * 搜索蓝牙装备     */    private void discoverBluetooth(){        if (mBluetoothAdapter.isDiscovering()) {            mBluetoothAdapter.cancelDiscovery();        }        //搜索装备        mBluetoothAdapter.startDiscovery();        mToast.showToast("正在搜索装备");    }    /**    点击变乱     */    @Override    public void onClick(View view) {        switch (view.getId()){            case R.id.open_bluetooth_btn:                //开启蓝牙                openBluetooth();                break;            case R.id.fount_device_btn:                //搜索装备                discoverBluetooth();                break;            default:                break;        }    }}Communication.java
package com.example.bluetoothdemo;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.Intent;import android.os.Bundle;import android.text.Editable;import android.text.TextWatcher;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ListView;import android.widget.TextView;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;import com.example.bluetoothdemo.utils.ToastUtil;import org.w3c.dom.Text;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.UUID;public class CommunicationActivity extends AppCompatActivity {    private EditText mEditText;    private Button mSendBtn;    private String mAddress;    private BluetoothAdapter mBlueToothAdapter;    private BluetoothDevice mDevice;    private BluetoothSocket mBluetoothSocket;    private final UUID mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//蓝牙串口服务的UUID    private ToastUtil mToast;    private TextView mReceiveContent;    private TextView mSendContent;    private TextView mCancelConn;    private String mSendContentStr;    private static OutputStream mOS;    private String TAG = "CommunicationActivity";    private String mName;    private TextView mBtName;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.communication_layout);        Intent intent = getIntent();        //得到传输过来的装备地点        mAddress = intent.getStringExtra("address");        mName = intent.getStringExtra("name");        initView();        initListener();        //开始毗连        connectDevice();    }    private void initView() {        mEditText = findViewById(R.id.send_edit_text);        mSendBtn = findViewById(R.id.send_text_btn);        mToast = new ToastUtil(this);        mReceiveContent = findViewById(R.id.received_text_content);        mSendContent = findViewById(R.id.send_text_content);        mCancelConn = findViewById(R.id.cancel_conn_btn);        mBtName = findViewById(R.id.bluetooth_name);        mBtName.setText(mName);    }    private void initListener() {        mSendBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mSendContentStr = mEditText.getText().toString();                //发送信息                sendMessage(mSendContentStr);            }        });        mCancelConn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                finish();            }        });    }    /**     * 发送数据的方法     * @param contentStr     */    private void sendMessage(String contentStr) {        if (mBluetoothSocket.isConnected()) {            try {                //获取输出流                mOS = mBluetoothSocket.getOutputStream();                if (mOS != null) {                    //写数据(参数为byte数组)                    mOS.write(contentStr.getBytes("GBK"));                    mEditText.getText().clear();                    mSendContent.append(contentStr);                    mToast.showToast("发送乐成");                }            } catch (IOException e) {                e.printStackTrace();            }        }else{            mToast.showToast("没有装备已毗连");        }    }    /**     * 与目的装备创建毗连     */    private void connectDevice() {        //获取默认蓝牙设配器        mBlueToothAdapter = BluetoothAdapter.getDefaultAdapter();        //通过地点拿到该蓝牙装备device        mDevice = mBlueToothAdapter.getRemoteDevice(mAddress);        try {            //创建socket通讯            mBluetoothSocket = mDevice.createRfcommSocketToServiceRecord(mUUID);            mBluetoothSocket.connect();            if (mBluetoothSocket.isConnected()) {                mToast.showToast("毗连乐成");                //开启吸收数据的线程                ReceiveDataThread thread = new ReceiveDataThread();                thread.start();            }else{                mToast.showToast("毗连失败,竣事重进");            }        } catch (IOException e) {            e.printStackTrace();            mToast.showToast("毗连堕落! ");            finish();            try {                mBluetoothSocket.close();            } catch (IOException ioException) {                ioException.printStackTrace();            }        }    }    @Override    protected void onDestroy() {        super.onDestroy();        try {            if (mBluetoothSocket.isConnected()) {                //关闭socket                mBluetoothSocket.close();                mBlueToothAdapter = null;            }        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 负责吸收数据的线程     */    public class ReceiveDataThread extends Thread{        private InputStream inputStream;        public ReceiveDataThread() {            super();            try {                //获取毗连socket的输入流                inputStream = mBluetoothSocket.getInputStream();            } catch (IOException e) {                e.printStackTrace();            }        }        @Override        public void run() {            super.run();            int len = 0;            byte[] buffer = new byte[256];            while (true){                try {                    inputStream.read(buffer);                    for (byte b : buffer) {                        Log.d(TAG,"b:" + b);                    }                    //设置GBK格式可以获取到中文信息,不会乱码                    String a = new String(buffer,0,buffer.length - 3,"GBK");//为什么-3 看文章末了留意部分                    Log.d(TAG,"a:" + a);//                    byte[] gbks = "你好".getBytes("GBK");//                    for (byte gbk : gbks) {//                        Log.d(TAG,"gbk:" + gbk);//                    }//                    String[] chars = a.split(" ");//                    String str = "";//                    for(int i = 0; i<chars.length;i++){//                        str += (char)Integer.parseInt(chars);//                    }                    //Log.d(TAG,"str:" + str);                    runOnUiThread(new Runnable() {                        @Override                        public void run() {                            //将收到的数据表现在TextView上                            mReceiveContent.append(a);                        }                    });                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}3、权限声明

<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>四、留意
我使用的这个和睦串口调试工具举行通讯测试时,我发现用它发完数据后,在手机端吸收到的数据的字节数组会多出3个字节,不知道是干什么用的。字节数组转汉字后会乱码,以是我就减去了末了3个字节。
还有编码格式要用GBK,否则汉字会乱码。不外在智能小车的数据传输中应该用不到汉字。
五、项目源码下载
源码+apk
https://download.csdn.net/download/weixin_44902943/14929360
GitHub:
https://github.com/gitHub-lgh/BlueToothSerialPort
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-24 15:30, Processed in 0.186460 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表