您的位置:首页 > 产品设计 > UI/UE

Android BlueTooth通信

2015-07-30 18:13 357 查看
简单来讲,写一个即作为客户端又作为服务端的蓝牙通信程序,需要三个线程来维持。

- 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蓝牙聊天(大数据分割,自定义包头)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: