关于怎样设置条记本电脑的蓝牙 串口而且和手机蓝牙配对,以及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 |