软件编程
位置:首页>> 软件编程>> Android编程>> Android实现蓝牙聊天功能

Android实现蓝牙聊天功能

作者:paul_zzq  发布时间:2023-06-10 01:19:48 

标签:Android,蓝牙聊天

蓝牙,时下最流行的智能设备传输数据的方式之一,通过手机app和智能设备进行连接,获取设备上的测量数据,我们生活中随处可见的比如蓝牙智能手环,蓝牙电子秤,蓝牙心电测量设备等等。

本篇我将紧接着上篇结尾所写,一起来看下手机之间如何通过蓝牙实现文字聊天。

先贴出上篇的一些demo;

Android实现蓝牙聊天功能

当点击图上的两个列表中的任何一个列表,执行如下代码:


mBtAdapter.cancelDiscovery();
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();

此蓝牙聊天工具最后实现的效果是这样的:

Android实现蓝牙聊天功能

将回到聊天主界面:


public void onActivityResult(int requestCode, int resultCode, Intent data) {
LogUtils.getInstance().e(getClass(), "onActivityResult " + resultCode);
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// 当DeviceListActivity返回与设备连接的消息
if (resultCode == Activity.RESULT_OK) {
// 连接设备的MAC地址
String address = data.getExtras().getString(
DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// 得到蓝牙对象
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// 开始连接设备
mChatService.connect(device);
}
break;
case REQUEST_ENABLE_BT:
// 判断蓝牙是否启用
if (resultCode == Activity.RESULT_OK) {
// 建立连接
setupChat();
} else {
LogUtils.getInstance().e(getClass(), "蓝牙未启用");
Toast.makeText(this, R.string.bt_not_enabled_leaving,
Toast.LENGTH_SHORT).show();
finish();
}
}
}

在此,我将重点介绍下BluetoothChatService类中的连接流程;
因为蓝牙聊天是两个手机之间进行通讯,所以他们互为主机和从机,主要思路以及步骤如下:

1.开一个线程获取socket去连接蓝牙;
2.开一个线程获监听蓝牙传入的连接,如果连接被接受的话,再开启第三个线程去处理所有传入和传出的数据;


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);
}

开线程去连接


/**
* @description:蓝牙连接线程
* @author:zzq
* @time: 2016-8-6 下午1:18:41
*/
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) {
LogUtils.getInstance().e(getClass(), "socket获取失败:" + e);
}
mmSocket = tmp;
}
public void run() {
LogUtils.getInstance().e(getClass(), "开始mConnectThread");
setName("ConnectThread");
// mAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
// 连接失败,更新ui
connectionFailed();
try {
mmSocket.close();
} catch (IOException e2) {
LogUtils.getInstance().e(getClass(), "关闭连接失败" + e2);
}
// 开启聊天接收线程
startChat();
return;
}
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
LogUtils.getInstance().e(getClass(), "关闭连接失败" + e);
}
}
}

/**
* 监听传入的连接
*/
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
LogUtils.getInstance().e(getClass(), "--获取socket失败:" + e);
}
mmServerSocket = tmp;
}

public void run() {
setName("AcceptThread");
BluetoothSocket socket = null;
while (mState != STATE_CONNECTED) {
LogUtils.getInstance().e(getClass(), "----accept-循环执行中-");
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
LogUtils.getInstance().e(getClass(), "accept() 失败" + e);
break;
}
// 如果连接被接受
if (socket != null) {
synchronized (BluetoothChatService.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) {
LogUtils.getInstance().e(getClass(),"不能关闭这些连接" + e);
}
break;

}
}
}
}
LogUtils.getInstance().e(getClass(), "结束mAcceptThread");
}

public void cancel() {
LogUtils.getInstance().e(getClass(), "取消 " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
LogUtils.getInstance().e(getClass(), "关闭失败" + e);
}
}
}
/**
* 连接成功后的线程 处理所有传入和传出的传输
*/
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;
// 得到BluetoothSocket输入和输出流
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
LogUtils.getInstance().e(getClass(),"temp sockets not created" + e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
int bytes;
String str1 = "";
// 循环监听消息
while (true) {
try {
byte[] buffer = new byte[256];
bytes = mmInStream.read(buffer);
String readStr = new String(buffer, 0, bytes);// 字节数组直接转换成字符串
String str = bytes2HexString(buffer).replaceAll("00", "").trim();
if (bytes > 0) {// 将读取到的消息发到主线程
 mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_READ, bytes, -1,buffer).sendToTarget();
} else {
 LogUtils.getInstance().e(getClass(),"disconnected");
connectionLost();
if (mState != STATE_NONE) {
LogUtils.getInstance().e(getClass(), "disconnected");
startChat();
}
break;
}
} catch (IOException e) {
LogUtils.getInstance().e(getClass(), "disconnected" + e);
connectionLost();
if (mState != STATE_NONE) {
// 在重新启动监听模式启动该服务
startChat();
}
break;
}
}
}
/**
* 写入OutStream连接
*
* @param buffer
* 要写的字节
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// 把消息传给UI
mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_WRITE, -1,-1, buffer).sendToTarget();

} catch (IOException e) {
LogUtils.getInstance().e(getClass(),
"Exception during write:" + e);
}

}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
LogUtils.getInstance().e(getClass(),"close() of connect socket failed:" + e);
}
}
}

大概的流程就是上面三个线程里面所展现的,当然具体情况,根据项目来,比如蓝牙协议协议解析这块的根据协议定义的方式来进行解析;

代码中牵扯的到的蓝牙连接状态的改变,用到的handle,直接把状态发送至activity,通知activity更新;


/**
* 无法连接,通知Activity
*/
private void connectionFailed() {
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChatActivity.TOAST, "无法连接设备");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* 设备断开连接,通知Activity
*/
private void connectionLost() {
Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChatActivity.TOAST, "设备断开连接");
msg.setData(bundle);
mHandler.sendMessage(msg);
}

当点击发送按钮时,将文本输入框中的文字发送数据的方法:


private void sendMessage(String message) {
if (mChatService.getState() != BluetoothChatService.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);
}
}
//调用BluetoothChatService类中的write进行数据发送
public void write(byte[] out) {
ConnectedThread r;
synchronized (this) {
if (mState != STATE_CONNECTED)
return;
r = mConnectedThread;
}
r.write(out);
}

如此,蓝牙聊天的流程就是这样,如果退出聊天的时候,停止所有线程;


public synchronized void stop() {
LogUtils.getInstance().e(getClass(), "---stop()");
setState(STATE_NONE);
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
}

相信看完本篇文章,在安卓蓝牙连接这块应该问题不大了(spp协议)。

源码地址:点我查看源码

来源:https://blog.csdn.net/paul_zzq/article/details/70799872

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com