安卓如何实现蓝牙通信?

  • 功能说明
  • 项目结构
  • 核心代码
  • 结果展示

功能说明

该程序主要实现蓝牙通信。具体功能有:
1、搜索附近蓝牙设备,并且能手动与周围设备发起蓝牙通信请求。
2、通信请求建立后,双方可以通过蓝牙进行文字的聊天。
3、用户可自定义自己的蓝牙设备是否能被周围的人发现。

项目结构

核心代码

/*MainActivity*/public class BluetoothChat extends AppCompatActivity {public static final int MESSAGE_STATE_CHANGE = 1;public static final int MESSAGE_READ = 2;public static final int MESSAGE_WRITE = 3;public static final int MESSAGE_DEVICE_NAME = 4;public static final int MESSAGE_TOAST = 5;public static final String DEVICE_NAME = "device_name";public static final String TOAST = "toast";private static final int REQUEST_CONNECT_DEVICE = 1;  //请求连接设备private static final int REQUEST_ENABLE_BT = 2;private TextView mTitle;private ListView mConversationView;private EditText mOutEditText;private Button mSendButton;private String mConnectedDeviceName = null;private ArrayAdapter<String> mConversationArrayAdapter;private StringBuffer mOutStringBuffer;private BluetoothAdapter mBluetoothAdapter = null;private ChatService mChatService = null;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getSupportActionBar().hide();  //隐藏标题栏if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);}}Toolbar toolbar = findViewById(R.id.toolbar);//创建选项菜单toolbar.inflateMenu(R.menu.option_menu);//选项菜单监听toolbar.setOnMenuItemClickListener(new MyMenuItemClickListener());mTitle = findViewById(R.id.title_left_text);mTitle.setText(R.string.app_name);mTitle = findViewById(R.id.title_right_text);// 得到本地蓝牙适配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (mBluetoothAdapter == null) {Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();finish();return;}if (!mBluetoothAdapter.isEnabled()) { //若当前设备蓝牙功能未开启Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableIntent, REQUEST_ENABLE_BT); //} else {if (mChatService == null) {setupChat();  //创建会话}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(grantResults.length>0){if(grantResults[0]!=PackageManager.PERMISSION_GRANTED){Toast.makeText(this, "未授权,蓝牙搜索功能将不可用!", Toast.LENGTH_SHORT).show();}}}@Overridepublic synchronized void onResume() {  //synchronized:同步方法实现排队调用super.onResume();if (mChatService != null) {if (mChatService.getState() == ChatService.STATE_NONE) {mChatService.start();}}}private void setupChat() {mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);mConversationView = findViewById(R.id.in);mConversationView.setAdapter(mConversationArrayAdapter);mOutEditText = findViewById(R.id.edit_text_out);mOutEditText.setOnEditorActionListener(mWriteListener);mSendButton = findViewById(R.id.button_send);mSendButton.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {TextView view = findViewById(R.id.edit_text_out);String message = view.getText().toString();sendMessage(message);}});//创建服务对象mChatService = new ChatService(this,mHandler);mOutStringBuffer = new StringBuffer("");}@Overridepublic void onDestroy() {super.onDestroy();if (mChatService != null)mChatService.stop();}private void ensureDiscoverable() { //修改本机蓝牙设备的可见性//打开手机蓝牙后,能被其它蓝牙设备扫描到的时间不是永久的if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);//设置在300秒内可见(能被扫描)discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);startActivity(discoverableIntent);Toast.makeText(this, "已经设置本机蓝牙设备的可见性,对方可搜索了。", Toast.LENGTH_SHORT).show();}}private void sendMessage(String message) {if (mChatService.getState() != ChatService.STATE_CONNECTED) {Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();return;}if (message.length() > 0) {byte[] send = message.getBytes();mChatService.write(send);mOutStringBuffer.setLength(0);mOutEditText.setText(mOutStringBuffer);}}private TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView view, int actionId, KeyEvent event) {if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {//软键盘里的回车也能发送消息String message = view.getText().toString();sendMessage(message);}return true;}};//使用Handler对象在UI主线程与子线程之间传递消息private final Handler mHandler = new Handler() {   //消息处理@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MESSAGE_STATE_CHANGE:switch (msg.arg1) {case ChatService.STATE_CONNECTED:mTitle.setText(R.string.title_connected_to);mTitle.append(mConnectedDeviceName);mConversationArrayAdapter.clear();break;case ChatService.STATE_CONNECTING:mTitle.setText(R.string.title_connecting);break;case ChatService.STATE_LISTEN:case ChatService.STATE_NONE:mTitle.setText(R.string.title_not_connected);break;}break;case MESSAGE_WRITE:byte[] writeBuf = (byte[]) msg.obj;String writeMessage = new String(writeBuf);mConversationArrayAdapter.add("我:  " + writeMessage);break;case MESSAGE_READ:byte[] readBuf = (byte[]) msg.obj;String readMessage = new String(readBuf, 0, msg.arg1);mConversationArrayAdapter.add(mConnectedDeviceName + ":  "+ readMessage);break;case MESSAGE_DEVICE_NAME:mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);Toast.makeText(getApplicationContext(),"链接到 " + mConnectedDeviceName, Toast.LENGTH_SHORT).show();break;case MESSAGE_TOAST:Toast.makeText(getApplicationContext(),msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show();break;}}};//返回进入好友列表操作后的数回调方法public void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case REQUEST_CONNECT_DEVICE:if (resultCode == Activity.RESULT_OK) {String address = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);mChatService.connect(device);} else if (resultCode == Activity.RESULT_CANCELED) {Toast.makeText(this, "未选择任何好友!", Toast.LENGTH_SHORT).show();}break;case REQUEST_ENABLE_BT:if (resultCode == Activity.RESULT_OK) {setupChat();} else {Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();finish();}}}//内部类,选项菜单的单击事件处理private class MyMenuItemClickListener implements Toolbar.OnMenuItemClickListener {@Overridepublic boolean onMenuItemClick(MenuItem item) {switch (item.getItemId()) {case R.id.scan://启动DeviceList这个ActivityIntent serverIntent = new Intent(BluetoothChat.this, DeviceList.class);startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);return true;case R.id.discoverable:ensureDiscoverable();return true;case R.id.back:finish();System.exit(0);return true;}return false;}}
}
/*聊天界面ChatService*/public class ChatService {//本应用的主Activity组件名称private static final String NAME = "BluetoothChat";// UUID:通用唯一识别码,是一个128位长的数字,一般用十六进制表示//算法的核心思想是结合机器的网卡、当地时间、一个随机数来生成//在创建蓝牙连接private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");private final BluetoothAdapter mAdapter;private final Handler mHandler;private AcceptThread mAcceptThread;private ConnectThread mConnectThread;private ConnectedThread mConnectedThread;private int mState;public static final int STATE_NONE = 0;public static final int STATE_LISTEN = 1;public static final int STATE_CONNECTING = 2;public static final int STATE_CONNECTED = 3;//构造方法,接收UI主线程传递的对象public ChatService(Context context, Handler handler) {//构造方法完成蓝牙对象的创建mAdapter = BluetoothAdapter.getDefaultAdapter();mState = STATE_NONE;mHandler = handler;}private synchronized void setState(int state) {mState = state;mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();}public synchronized int getState() {return mState;}public synchronized void start() {if (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}if (mConnectedThread != null) {mConnectedThread.cancel();mConnectedThread = null;}if (mAcceptThread == null) {mAcceptThread = new AcceptThread();mAcceptThread.start();}setState(STATE_LISTEN);}//取消 CONNECTING 和 CONNECTED 状态下的相关线程,然后运行新的 mConnectThread 线程public synchronized void connect(BluetoothDevice device) {if (mState == STATE_CONNECTING) {if (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}}if (mConnectedThread != null) {mConnectedThread.cancel();mConnectedThread = null;}mConnectThread = new ConnectThread(device);mConnectThread.start();setState(STATE_CONNECTING);}/*开启一个 ConnectedThread 来管理对应的当前连接。之前先取消任意现存的 mConnectThread 、mConnectedThread 、 mAcceptThread 线程,然后开启新 mConnectedThread ,传入当前刚刚接受的socket 连接。最后通过 Handler来通知UI连接*/public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {if (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}if (mConnectedThread != null) {mConnectedThread.cancel();mConnectedThread = null;}if (mAcceptThread != null) {mAcceptThread.cancel();mAcceptThread = null;}mConnectedThread = new ConnectedThread(socket);mConnectedThread.start();Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());msg.setData(bundle);mHandler.sendMessage(msg);setState(STATE_CONNECTED);}// 停止所有相关线程,设当前状态为 NONEpublic synchronized void stop() {if (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}if (mConnectedThread != null) {mConnectedThread.cancel();mConnectedThread = null;}if (mAcceptThread != null) {mAcceptThread.cancel();mAcceptThread = null;}setState(STATE_NONE);}// 在 STATE_CONNECTED 状态下,调用 mConnectedThread 里的 write 方法,写入 bytepublic void write(byte[] out) {ConnectedThread r;synchronized (this) {if (mState != STATE_CONNECTED)return;r = mConnectedThread;}r.write(out);}// 连接失败的时候处理,通知 ui ,并设为 STATE_LISTEN 状态private void connectionFailed() {setState(STATE_LISTEN);Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.TOAST, "链接不到设备");msg.setData(bundle);mHandler.sendMessage(msg);}// 当连接失去的时候,设为 STATE_LISTEN 状态并通知 uiprivate void connectionLost() {setState(STATE_LISTEN);Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.TOAST, "设备链接中断");msg.setData(bundle);mHandler.sendMessage(msg);}// 创建监听线程,准备接受新连接。使用阻塞方式,调用 BluetoothServerSocket.accept()private class AcceptThread extends Thread {private final BluetoothServerSocket mmServerSocket;public AcceptThread() {BluetoothServerSocket tmp = null;try {//使用射频端口(RF comm)监听tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {}mmServerSocket = tmp;}@Overridepublic void run() {setName("AcceptThread");BluetoothSocket socket = null;while (mState != STATE_CONNECTED) {try {socket = mmServerSocket.accept();} catch (IOException e) {break;}if (socket != null) {synchronized (ChatService.this) {switch (mState) {case STATE_LISTEN:case STATE_CONNECTING:connected(socket, socket.getRemoteDevice());break;case STATE_NONE:case STATE_CONNECTED:try {socket.close();} catch (IOException e) {e.printStackTrace();}break;}}}}}public void cancel() {try {mmServerSocket.close();} catch (IOException e) {e.printStackTrace();}}}/*连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。构造函数里通过 BluetoothDevice.createRfcommSocketToServiceRecord() ,从待连接的 device 产生 BluetoothSocket. 然后在 run 方法中 connect ,成功后调用 BluetoothChatSevice 的 connected() 方法。定义 cancel() 在关闭线程时能够关闭相关socket 。*/private class ConnectThread extends Thread {private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {mmDevice = device;BluetoothSocket tmp = null;try {tmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {e.printStackTrace();}mmSocket = tmp;}@Overridepublic void run() {setName("ConnectThread");mAdapter.cancelDiscovery();try {mmSocket.connect();} catch (IOException e) {connectionFailed();try {mmSocket.close();} catch (IOException e2) {e.printStackTrace();}ChatService.this.start();return;}synchronized (ChatService.this) {mConnectThread = null;}connected(mmSocket, mmDevice);}public void cancel() {try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}}}/*双方蓝牙连接后一直运行的线程;构造函数中设置输入输出流。run()方法中使用阻塞模式的 InputStream.read()循环读取输入流,然后发送到 UI 线程中更新聊天消息。本线程也提供了 write() 将聊天消息写入输出流传输至对方,传输成功后回写入 UI 线程。最后使用cancel()关闭连接的 socket*/private class ConnectedThread extends Thread {private final BluetoothSocket mmSocket;private final InputStream mmInStream;private final OutputStream mmOutStream;public ConnectedThread(BluetoothSocket socket) {mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut = null;try {tmpIn = socket.getInputStream();tmpOut = socket.getOutputStream();} catch (IOException e) {e.printStackTrace();}mmInStream = tmpIn;mmOutStream = tmpOut;}@Overridepublic void run() {byte[] buffer = new byte[1024];int bytes;while (true) {try {bytes = mmInStream.read(buffer);mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer).sendToTarget();} catch (IOException e) {connectionLost();break;}}}public void write(byte[] buffer) {try {mmOutStream.write(buffer);mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();} catch (IOException e) {e.printStackTrace();}}public void cancel() {try {mmSocket.close();} catch (IOException e) {e.printStackTrace();}}}
}

activity布局效果:

结果展示

这个程序在虚拟机上跑是看不出效果的,所以最好连接一下真机,具体安卓连接真机可以参考这一篇11111111111
连接上真机后,不用打开设备管理器查看手机,直接打开AS,会看到我的华为:

在真机上就是这么个效果:




这是本人的gitee
本人的gitee
参考链接:
http://www.wustwzx.com/as/sy/sy09.html#mk2

作业六:安卓实现蓝牙通信相关推荐

  1. Android Studio开发(六)短距离无线通信——蓝牙通信

    Android Studio开发(六)短距离无线通信--蓝牙通信 Android Studio开发(六)蓝牙通信 一.任务需求 二.短距离无线通信技术(Short-Distance Wirleless ...

  2. 移动开发作业6——蓝牙通信的简要设计与开发

    一.蓝牙通信原理介绍 Android 平台包含蓝牙网络堆栈支持,此支持能让设备以无线方式与其他蓝牙设备交换数据.应用框架提供通过 Android Bluetooth API 访问蓝牙功能的权限.这些 ...

  3. Android Studio开发之蓝牙通信

    安卓开发-蓝牙通信 功能需求:在微信程序的第一子项中完成"蓝牙聊天功能" 开发步骤: 配置文件注册 设计界面布局 编写用于蓝牙会话的服务组件ChatService 分别建立供主Ac ...

  4. 移动开发作业六 蓝牙通信

    一.蓝牙通信的步骤 开启蓝牙 搜索可用设备 创建蓝牙socket 获取输入输出流 断开连接关闭蓝牙 二.几个重要的类 BluetoothAdapter BluetoothGatt BluetoothD ...

  5. 手机APP开发之MIT Appinventor详细实战教程(六),蓝牙与单片机进行多数据交互,通信蓝牙控制APP的研发与设计。 以及相关问题的思考。

    目录 一.App的简单介绍 二.蓝牙逻辑连接的实现 三.数据比较逻辑结构的实现 四.数据显示遇到的问题和思考 五.解决方法和尝试 六.问题分析与寻求帮助 七.总结 一.App的简单介绍 首先APP的功 ...

  6. 安卓开发实现蓝牙通信——两设备相互发消息

    功能说明: 实现设备之间通过蓝牙进行通信 两个设备之间互发消息 实验步骤 (1)在两个手机分别安装.运行本应用.如果未打开手机蓝牙,则进入打开蓝牙设置界面:     (2)在OptionMenu(选项 ...

  7. python写安卓app控制蓝牙_基于python实现蓝牙通信代码实例

    这篇文章主要介绍了基于python实现蓝牙通信代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 安装和示例 linux下安装 sudo apt ...

  8. Android Studio 蓝牙通信BlueTooth

    BlueTooth蓝牙通信 作业内容 配置蓝牙使用权限 页面布局 Layout文件夹中 Values文件夹中 Menu文件夹中 事件监听控制 服务组件ChatService.java weixinFr ...

  9. 实现Android和PC之间的蓝牙通信

    这两天想实现PC和安卓手机的通信,限于水平,知道的方法大概有两种:基于数据包的socket和蓝牙.虽然看起来简单,但调也调了两天多.自己测试了下socket,在室内WIFI环境下时延大概是0.1s.而 ...

最新文章

  1. 2021年中国工业互联网安全大赛核能行业赛道writeup之传统流量取证
  2. Java - 网络编程(NetWork)
  3. html百度地图app,uniapp H5 百度地图(示例代码)
  4. 使用Ubuntu 12.04作为日常电脑环境
  5. EdgeGallery:聚焦 5 大行业场景,MEC 开源平台将 5G 能力拓展到边缘
  6. mongodb运算操作符
  7. Tampermonkey版Vimium
  8. C++socket编程(七):7.4 正则表达式分析用户请求
  9. Lightroom Classic 教程,如何在 Lightroom 中使用面部识别整理照片?
  10. 白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 ManualResetEvent...
  11. linux中可以使用-af含义,关于Windows中的linux:AF_UNIX
  12. 计算机网络常见面试题
  13. Unity UI框架思路与实现
  14. android webview加载图片不显示,解决android webview中图片不显示问题
  15. 本科学计算机大学学金融工程,2020年金融工程专业排名
  16. 程序设计实践-21点赌博游戏
  17. Java导出Excel,提示格式与文件扩展名不一致
  18. 99乘法表带颜色HTML隔行变色,javascript小实例,实现99乘法表及隔行变色
  19. NB模组(BC28/NB86-G)使用域名接入华为云方法
  20. 高精密库仑计DS2740驱动程序

热门文章

  1. Jmeter RSA动态加密解密
  2. minio存储之纠删码(Erasure Code)
  3. 程序人生 - 提前冲线!10名浙江高中生不用高考,直接被清华大学录取,杭州4位学霸来自这些学校
  4. 一个基于Python数据大屏可视化开源项目
  5. ygbook和ptcms哪个好_杰奇CMS 和 PTCMS 有什么区别? 为什么很多人选择杰奇?
  6. ptcms模板自动采集小说系统源码
  7. 高数_证明_高斯公式
  8. SOP(标准操作流程)
  9. 2023年PMP考试内容有哪些?怎么备考?
  10. 初识App Inventor 2(AI2)