Android BlueTooth通信
2015-07-30 18:13
357 查看
简单来讲,写一个即作为客户端又作为服务端的蓝牙通信程序,需要三个线程来维持。
- 1,AcceptThread:等待客户端连接线程
- 2,ConnectThread:作为客户端连接指定的蓝牙设备线程
- 3,ConnectedThread:蓝牙设备间数据的传输线程
若实现服务端程序,使用1,3组合。客户端程序,使用2,3组合。
在实现蓝牙通信过程中,遇到如下几个问题:
1. 如何监听蓝牙连接及断开的状态。
2. 大数据传输时,如何保证数据完整性。
3. 图片,资源文件如何传输。
4. 。。。未发现的问题。。。
贴代码
线程被定义在Service中,在初始化Service时做如下操作:
源码下载地址:Android蓝牙聊天(大数据分割,自定义包头)
- 1,AcceptThread:等待客户端连接线程
- 2,ConnectThread:作为客户端连接指定的蓝牙设备线程
- 3,ConnectedThread:蓝牙设备间数据的传输线程
若实现服务端程序,使用1,3组合。客户端程序,使用2,3组合。
在实现蓝牙通信过程中,遇到如下几个问题:
1. 如何监听蓝牙连接及断开的状态。
2. 大数据传输时,如何保证数据完整性。
3. 图片,资源文件如何传输。
4. 。。。未发现的问题。。。
贴代码
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; private boolean isCancel = false; public AcceptThread() { Log.d(TAG, "AcceptThread"); BluetoothServerSocket tmp = null; try { tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("MT_Chat_Room", UUID.fromString(UUID_STR)); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; while (true) { try { // 阻塞等待 socket = mmServerSocket.accept(); } catch (Exception e) { if (!isCancel) { try { mmServerSocket.close(); } catch (Exception e1) { } mAcceptThread = new AcceptThread(); mAcceptThread.start(); isServerMode = true; } break; } if (socket != null) { manageConnectedSocket(socket); try { mmServerSocket.close(); } catch (IOException e) { } mAcceptThread = null; break; } } } public void cancel() { try { Log.d(TAG, "AcceptThread canceled"); isCancel = true; isServerMode = false; mmServerSocket.close(); mAcceptThread = null; if (mCommThread != null && mCommThread.isAlive()) { mCommThread.cancel(); } } catch (IOException e) { } } } private ConnectedThread mConnThread; private void manageConnectedSocket(BluetoothSocket socket) { // 启动子线程来维持连接 mConnThread = new ConnectedThread(socket); mConnThread.start(); } /** * 作为客户端连接指定的蓝牙设备线程 */ private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { Log.d(TAG, "ConnectThread"); if (mAcceptThread != null && mAcceptThread.isAlive()) { mAcceptThread.cancel(); } if (mConnThread != null && mConnThread.isAlive()) { mConnThread.cancel(); } // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; try { tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID_STR)); } catch (IOException e) { Log.d(TAG, "createRfcommSocketToServiceRecord error!"); } mmSocket = tmp; } public BluetoothDevice getDevice() { return mmDevice; } public void run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery(); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and get out Log.e(TAG, "Connect server failed"); try { mmSocket.close(); } catch (IOException closeException) { } mAcceptThread = new AcceptThread(); mAcceptThread.start(); isServerMode = true; return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } mConnectThread = null; } } /** * 蓝牙设备间数据的传输线程 */ private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; private BufferedOutputStream mmBos; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; mmBos = new BufferedOutputStream(mmOutStream); } public OutputStream getOutputStream() { return mmOutStream; } public boolean write(byte[] msg) { if (msg == null) return false; try { mmBos.write(msg); mmBos.flush(); } catch (IOException e) { return false; } return true; } public String getRemoteName() { return mmSocket.getRemoteDevice().getName(); } public void cancel() { try { mmSocket.close(); } catch (Exception e) { } mConnThread = null; } public void run() { try { write(DataProtocol.GroupMsg(mBluetoothAdapter.getName() + "已经上线")); } catch (UnsupportedEncodingException e2) { } Message msg = new Message(); android.os.Message handlerMsg; HashMap<String, Object> data; int size = 0, allSize = 0, readCount = 0; byte[] allbuffer = null, tempbuffer; while (true) { try { while (readCount == 0 || readCount < allSize) { while (size == 0) { size = mmInStream.available(); } tempbuffer = new byte[size]; Log.i("bluetooth", "mmInStream.available() " + size); mmInStream.read(tempbuffer); if (allSize == 0) { byte[] head = new byte[DataProtocol.haedLen]; System.arraycopy(tempbuffer, 0, head, 0, DataProtocol.haedLen); if (head[0] == DataProtocol.HEAD && head[1] == DataProtocol.TYPE_MSG) { byte[] conLen = new byte[] { head[2], head[3] }; allSize = DataProtocol.toInt(conLen); // 数据包长度 allbuffer = new byte[allSize]; Log.i("bluetooth", "allSize " + allSize); } } int contentLen = 0; if (readCount + tempbuffer.length > allSize) { contentLen = allSize - readCount; } else { contentLen = tempbuffer.length; } System.arraycopy(tempbuffer, 0, allbuffer, readCount, contentLen); readCount += tempbuffer.length; Log.i("bluetooth", "readCount " + readCount); } allSize = readCount = 0; Log.i("bluetooth", "allbuffer length " + allbuffer.length); Message tempMsg = DataProtocol.unpackData(allbuffer); if (tempMsg == null) continue; msg.msg = tempMsg.msg; msg.type = DataProtocol.TYPE_MSG; if (mActivityHandler == null) { return; } msg.remoteDevName = mmSocket.getRemoteDevice().getName(); if (msg.type == DataProtocol.TYPE_FILE) { // 文件接收处理忽略 } else if (msg.type == DataProtocol.TYPE_MSG) { data = new HashMap<String, Object>(); System.out.println("Read data."); data.put(ChatListViewAdapter.KEY_ROLE, ChatListViewAdapter.ROLE_TARGET); data.put(ChatListViewAdapter.KEY_NAME, msg.remoteDevName); data.put(ChatListViewAdapter.KEY_TEXT, msg.msg); // 通过Activity更新到UI上 handlerMsg = mActivityHandler.obtainMessage(); handlerMsg.what = Task.TASK_RECV_MSG; handlerMsg.obj = data; mActivityHandler.sendMessage(handlerMsg); } } catch (Exception e) { Log.i("bluetooth", "encode error " + e.getMessage()); try { mmSocket.close(); } catch (IOException e1) { } mConnThread = null; if (isServerMode) { // 检查远程设备状态 handlerMsg = mServiceHandler.obtainMessage(); handlerMsg.what = Task.TASK_GET_REMOTE_STATE; mServiceHandler.sendMessage(handlerMsg); SoundEffect.getInstance(TaskService.this).play(2); mAcceptThread = new AcceptThread(); mAcceptThread.start(); } break; } } } }
线程被定义在Service中,在初始化Service时做如下操作:
@Override public void onCreate() { super.onCreate(); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Log.e(TAG, "Your device is not support Bluetooth!"); return; } mThread = new TaskThread(); mThread.start(); IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); this.registerReceiver(ACLReceiver, filter); }
源码下载地址:Android蓝牙聊天(大数据分割,自定义包头)
相关文章推荐
- MUI - 解决bug: iphone页面保存时popPicker自动弹出来
- ERROR 1366 (HY000): Incorrect string value: '\xE4\xBD\xA0\xE5\xA5\xBD' for column 'name' at row 1
- @RequestParam @RequestBody @PathVariable
- iOS学习笔记2-使用Audio Queues录音,取得实时PCM数据
- UITableView 实现类似btn单选功能
- Selenium2学习-019-WebUI自动化实战实例-017-获取浏览器类型
- ui automation viewer 工具
- 解析iptables中SNAT和MASQUERADE之间的区别
- navigationItem中加入UISegmentedControl
- IOS开发 UITableView empty 简单实用
- the constructor AlertDialog.Builder(new View.OnClickListener() ) is undefined
- pcDuino使用问题总结
- UIViewController的生命周期及iOS程序执行顺序
- zozoui
- Arduino开发环境搭建
- 百度编辑器ueditor的简单使用
- [Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
- Truncated incorrect DOUBLE value: '172.31.27.3'错误原因及解决方案
- 杂烩:QWiget、QGraphics、QtQuick
- iOS阶段学习第28天笔记(UIView的介绍)