Android实现蓝牙聊天功能
一、前言
随着移动设备的普及,蓝牙技术已经成为一种常见的无线通信方式,在Android平台上,通过蓝牙实现设备之间的数据传输和通讯是一种非常实用的功能,本文将详细讲解如何在Android应用中实现一个简单的蓝牙聊天功能,包括蓝牙的搜索、配对、连接以及数据的发送和接收。
二、准备工作
在开始编写代码之前,需要确保开发环境配置正确,以下是所需的工具和库:
1、Android Studio: 官方集成开发环境(IDE)。
2、BluetoothAdapter: Android提供的用于管理蓝牙功能的类。
3、BluetoothSocket: 用于蓝牙通信的套接字。
4、BluetoothDevice: 表示远程蓝牙设备。
5、Handler: 用于处理消息传递。
6、Message: 用于封装信息。
7、UUID: 通用唯一识别码,用于标识服务。
三、项目结构
为了便于管理和理解,建议按照以下目录结构组织项目:
src/main/java
com.example.bluetoothchat
BluetoothChatActivity.java
: 主活动类。
BluetoothService.java
: 蓝牙服务类。
Constants.java
: 常量定义文件。
MessageHandler.java
: 消息处理类。
四、常量定义 (Constants.java)
package com.example.bluetoothchat; public class Constants { public static final String DEVICE_NAME = "MyBluetoothChat"; // 设备名称 public static final UUID MY_UUID = java.util.UUID.randomUUID(); // 随机生成一个UUID }
五、蓝牙服务类 (BluetoothService.java)
这个类负责蓝牙的初始化、搜索、配对和连接等操作。
package com.example.bluetoothchat; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; public class BluetoothService { private static final String TAG = "BluetoothService"; private static final int STATE_NONE = 0; // we're doing nothing private static final int STATE_LISTEN = 1; // now listening for incoming connections private static final int STATE_CONNECTING = 2; // there is an active connection private static final int STATE_CONNECTED = 3; // now connected to a remote device private BluetoothAdapter mAdapter; private Context mContext; private Handler mHandler; private AcceptThread mAcceptThread; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; private int mState; private UUID mUUID; private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME, device).sendToTarget(); } }; public BluetoothService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; mUUID = Constants.MY_UUID; mContext = context; } private synchronized void setState(int state) { mState = state; mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } private synchronized void start() { if (D) Log.d(TAG, "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); } if (mScanning) { mAdapter.stopLeScan(mLeScanCallback); setState(STATE_NONE); return; } } private synchronized void connect(BluetoothDevice device) { if (D) Log.d(TAG, "connect to: " + 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); } private synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { if (D) Log.d(TAG, "connected"); 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(); setState(STATE_CONNECTED); Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString("toast", "Connected to " + device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); } private synchronized void stop() { if (D) Log.d(TAG, "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); } public synchronized void write(byte[] out) { Log.d(TAG, "write: Write message: " + new String(out)); if (mConnectedThread != null) { mConnectedThread.write(out); } else { Log.w(TAG, "write: Not connected"); } } public void startDiscovery() { if (mAdapter.isDiscovering()) { mAdapter.cancelDiscovery(); } else { mAdapter.startDiscovery(); } } // Create a new server socket using the UUID from the profile name and listen for incoming connections. private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; private String mSocketType; public AcceptThread() { BluetoothServerSocket tmp = null; mSocketType = "Secure"; try { if (secure) { tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } else { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); mSocketType = "Insecure"; } } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "createListener() failed", e); } mmServerSocket = tmp; mAdapter.cancelDiscovery(); } public void run() { if (D) Log.d(TAG, "BEGIN mAcceptThread" + this); setName("AcceptThread"); BluetoothSocket socket = null; while (mState != STATE_CONNECTED) { try { socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "accept() failed", e); break; } if (socket != null) { synchronized (BluetoothService.this) { switch (mState) { case STATE_LISTEN: case STATE_CONNECTTHEM: connected(socket, socket.getRemoteDevice()); break; case STATE_NONE: case STATE_CONNECTED: try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close unwanted socket", e); } break; } } } } if (D) Log.i(TAG, "END mAcceptThread", this); setState(STATE_NONE); mAcceptThread = null; if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mmServerSocket != null) { try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close server socket", e); } } } void cancel() { mAcceptThread.interrupt(); } } // This thread runs while attempting to make an outgoing connection with a device. It runs until it either: establishes a connection and returns or each connection attempt fails to connect then records a message and quits. private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; mSocketType = "Secure"; try { if (secure) { tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } else { tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID); mSocketType = "Insecure"; } } catch (IOException e) { Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); } mmSocket = tmp; } public void run() { mAdapter.cancelDiscovery(); setName("ConnectThread"); setState(STATE_CONNECTING); try { mmSocket.connect(); } catch (IOException e) { connectionFailed(); try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2); } return; } finally { } connected(mmSocket, mmDevice); } void cancel() { try { mmSocket.close(); } catch (IOException e) { } because you cannot reliably close input stream here due to possible blocking by buffered I/O operations System.exit(0); } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } ) new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; String action = new String(readBuf, 0, msg.arg1, "utf-8"); if (true) { Log.d(TAG, "Read: " + action); } return true; case MESSAGE_WRITE: byte[] writeBuf = (byte[]) msg.obj; Integer wrote = msg.arg1; if (true) { Log.d(TAG, "Write: " + new String(writeBuf, 0, writeBuf.length, "utf-8")); } return true; case MESSAGE_DEVICE_NAME: msg.obj = msg.obj + " Rename me"; break; case MESSAGE_TOAST: Toast msg = msg.obj; msg.show(); break; case MESSAGE_STATE_CHANGE: switch (msg.arg1) { case BluetoothService.STATE_NONE: break; case BluetoothService.STATE_LISTEN: break; case BluetoothService.STATE_CONNECTING: break; case BluetoothService.STATE_CONNECTED: break; case BluetoothService.STATE_MESSAGE_READ: break; default: break; } break; default: super.handleMessage(msg); } } ); 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) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; int numBytes; while (true) { try { numBytes = mmInStream.read(buffer); String readMessage = new String(buffer, 0, numBytes, "UTF-8"); mHandler.obtainMessage(BluetoothService.MESSAGE_READ, buffer, 0, numBytes).sendToTarget(); } catch (IOException e) { Log.d(TAG, "Input stream was disconnected", e); break; } } } void write(byte[] bytes) { try { mmOutStream.write(bytes); mHandler.obtainMessage(BluetoothService.MESSAGE_WRITE, bytes, bytes.length).sendToTarget(); } catch (IOException e) { Log.e(TAG, "Error occurred when sending data", e); break; } finally { try { mmInStream.close(); } catch (IOException e) { Log.e(TAG, "Error closing input stream", e); } catch (NullPointerException e2) { Log.e(TAG, "Null pointer exception on input stream close", e2); } finally { try { mmOutStream.close(); } catch (IOException e) { Log.e(TAG, "Error closing output stream", e); } catch (NullPointerException e2) { Log.e(TAG, "Null pointer exception on output stream close", e2); } finally { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "Error closing socket", e); } finally { super.finalize(); } }}}}};```
各位小伙伴们,我刚刚为大家分享了有关“Android实现蓝牙聊天功能”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!