安卓蓝牙操作+蓝牙工具类
由于前段时间,需要蓝牙操作一些东西。但是没有写过蓝牙连接与蓝牙操作等一系列的东西。
然后就去网上找找大家写的。到现在。已经结束了这个蓝牙的开发。
安卓端蓝牙操作。主要需要如下类
BluetoothAdapter 通过名字,可以了解到这是一个蓝牙适配器的类。可以获取到蓝牙的状态。开关,。扫描等一系列的常规操作
BluetoothSocket 这个呢,是一个蓝牙的socket。不做过多的介绍。和普通socket一样
BluetoothDevice 这个类是获取远程设备的类。
有了上面3个类。蓝牙的基本操作就可以实现了。
当然。,蓝牙的操作需要广播来支持、。下面是具体的代码。
蓝牙相关广播
Action值 说明
ACTION_STATE_CHANGED 蓝牙状态值发生改变
ACTION_SCAN_MODE_CHANGED 蓝牙扫描状态(SCAN_MODE)发生改变
ACTION_DISCOVERY_STARTED 蓝牙扫描过程开始
ACTION_DISCOVERY_FINISHED 蓝牙扫描过程结束
ACTION_LOCAL_NAME_CHANGED 蓝牙设备Name发生改变
ACTION_REQUEST_DISCOVERABLE 请求用户选择是否使该蓝牙能被扫描
PS:如果蓝牙没有开启,用户点击确定后,会首先开启蓝牙,继而设置蓝牙能被扫描。
ACTION_REQUEST_ENABLE 请求用户选择是否打开蓝牙
ACTION_FOUND (该常量字段位于BluetoothDevice类中)
说明:蓝牙扫描时,扫描到任一远程蓝牙设备时,会发送此广播。
private BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {//开始扫描蓝牙时候的广播 mDeviceList.clear(); mAdapter.notifyDataSetChanged(); } if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //这个广播是扫描结束,蓝牙发送的广播 if (progressDialog!=null){ progressDialog.cancel(); progressDialog=null; } showToast("搜素完成"); } if (BluetoothDevice.ACTION_FOUND.equals(action)) { //当扫描到蓝牙设备时,会发送这个广播 mDeviceList.add((BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); mAdapter.notifyDataSetChanged(); } if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) { //蓝牙扫描状态(SCAN_MODE)发生改变 if (intent.getIntExtra("android.bluetooth.adapter.extra.SCAN_MODE", 0) == 23) { } } if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { //绑定时候的广播 BluetoothDevice remoteDevice = (BluetoothDevice) intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE"); if (remoteDevice == null) { showToast("no device"); return; } int status = intent.getIntExtra("android.bluetooth.device.extra.BOND_STATE", 0); if (status == 12) { showToast("配对完成 " + remoteDevice.getName()); blueToothUtils.searchDevices(); showToast("刷新列表中 "); } else if (status == 11) { showToast("正在配对 " + remoteDevice.getName()); } else if (status == 10) { showToast("配对失败 " + remoteDevice.getName()); } } } };
//设置要监听的广播。
void initView(){
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
mContext.registerReceiver(mReceiver, filter);
}
上面的设置完成以后
编写一个蓝牙工具类进行使用。方便以后的开发。
在一开始。网上找了一些蓝牙的操作工具类。但是多多少少都有写瑕疵。
大多数都是2个手机通信。无法和蓝牙单片机模块通信。
具体的蓝牙操作类如下,这个工具类都是我在网上的大多数工具类中攒在一起的。里面有些方法也没用。我也就不删了。在接收数据的时候。如果是单片机发过来的话,数据会接收不完全。这里,将原来类方法更改了一下。、大家在接收数据时,尽量选择一个用不到的数字或者字母等,来当做结束位。进行判断、工具类里面的注释基本都有。
在网上找资料时,发现2个工具类,一个如下,看着比较简单,大家容易懂,还有一个。都是英文,后面翻译了一下,也放在文章最后吧。其实思路都一样。喜欢那个,用那个
工具类如下:
public class BlueToothUtils { private static final String TAG = "BlueToothUtils"; private Context mContext; public static BlueToothUtils sInstance; private BluetoothAdapter mBA; private SharedPreferences sp; // UUID.randomUUID()随机获取UUID private final UUID MY_UUID = UUID .fromString("00001101-0000-1000-8000-00805F9B34FB"); // 连接对象的名称 private final String NAME = "Chaoba"; // 这里本身即是服务端也是客户端,需要如下类 private BluetoothSocket mSocket; private BluetoothDevice mOldDevice; private BluetoothDevice mCurDevice; // 输出流_客户端需要往服务端输出 private OutputStream os; private InputStream inputStream; //线程类的实例 private AcceptThread ac; private Handler mhandler; private Handler handler2; private BlueToothUtils.Readtask readtask; public static synchronized BlueToothUtils getInstance() { if (sInstance == null) { sInstance = new BlueToothUtils(); } return sInstance; } public BlueToothUtils() { mBA = BluetoothAdapter.getDefaultAdapter(); ac = new AcceptThread(); } public void setContext(Context context) { this.mContext = context; } public void setHandler(Handler handler){ this.mhandler=handler; } public void setHandler2(Handler handler2){ this.handler2=handler2; } public BluetoothAdapter getBA() { return mBA; } public AcceptThread getAc() { return ac; } public BluetoothDevice getCurDevice() { return mCurDevice; } /** * 判断是否打开蓝牙 * * @return */ public boolean isEnabled() { if (mBA.isEnabled()) { return true; } return false; } /** * 搜索设备 */ public void searchDevices() { // 判断是否在搜索,如果在搜索,就取消搜索 if (mBA.isDiscovering()) { mBA.cancelDiscovery(); } // 开始搜索 mBA.startDiscovery(); Log.e(TAG, "正在搜索..."); } /** * 获取已经配对的设备 * * @return */ public List<BluetoothDevice> getBondedDevices() { List<BluetoothDevice> devices = new ArrayList<>(); Set<BluetoothDevice> pairedDevices = mBA.getBondedDevices(); // 判断是否有配对过的设备 if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { devices.add(device); Log.e(TAG, "BondedDevice:" + device.getName()); } } return devices; } /** * 与设备配对 * * @param device */ public void createBond(BluetoothDevice device) { try { Method createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } } /** * 与设备解除配对 * * @param device */ public void removeBond(BluetoothDevice device) { try { Method removeBondMethod = device.getClass().getMethod("removeBond"); removeBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } } /** * * @param device * @param str 设置PIN码 * @return */ public boolean setPin(BluetoothDevice device, String str) { try { Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class}); Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{str.getBytes()}); Log.e("returnValue", "" + returnValue); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return true; } /** * 取消用户输入 */ public boolean cancelPairingUserInput(BluetoothDevice device) { Boolean returnValue = false; try { Method createBondMethod = device.getClass().getMethod("cancelPairingUserInput"); returnValue = (Boolean) createBondMethod.invoke(device); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } // cancelBondProcess() return returnValue.booleanValue(); } /** * 取消配对 */ public boolean cancelBondProcess(BluetoothDevice device) { Boolean returnValue = null; try { Method createBondMethod = device.getClass().getMethod("cancelBondProcess"); returnValue = (Boolean) createBondMethod.invoke(device); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return returnValue.booleanValue(); } /** * @param strAddr * @param strPsw * @return */ public boolean pair(String strAddr, String strPsw) { boolean result = false; mBA.cancelDiscovery(); if (!mBA.isEnabled()) { mBA.enable(); } if (!BluetoothAdapter.checkBluetoothAddress(strAddr)) { // 检查蓝牙地址是否有效 Log.d("mylog", "devAdd un effient!"); } BluetoothDevice device = mBA.getRemoteDevice(strAddr); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { Log.d("mylog", "NOT BOND_BONDED"); try { setPin(device, strPsw); // 手机和蓝牙采集器配对 createBond(device); result = true; } catch (Exception e) { Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } // } else { Log.d("mylog", "HAS BOND_BONDED"); try { createBond(device); setPin(device, strPsw); // 手机和蓝牙采集器配对 createBond(device); result = true; } catch (Exception e) { Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } } return result; } /** * 获取device.getClass()这个类中的所有Method * * @param clsShow */ public void printAllInform(Class clsShow) { try { // 取得所有方法 Method[] hideMethod = clsShow.getMethods(); int i = 0; for (; i < hideMethod.length; i++) { Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i); } // 取得所有常量 Field[] allFields = clsShow.getFields(); for (i = 0; i < allFields.length; i++) { Log.e("Field name", allFields[i].getName()); } } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 打开蓝牙 */ public void openBlueTooth() { if (!mBA.isEnabled()) { // 弹出对话框提示用户是后打开 /*Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 1);*/ // 不做提示,强行打开 mBA.enable(); showToast("打开蓝牙"); } else { showToast("蓝牙已打开"); } } /** * 关闭蓝牙 */ public void closeBlueTooth() { mBA.disable(); showToast("关闭蓝牙"); } /** * 弹出Toast窗口 * * @param message */ private void showToast(String message) { if (mContext != null) { Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); } else { Log.e(TAG, "message:" + message); } } /** * 主动连接蓝牙 * * @param device */ public void connectDevice(BluetoothDevice device) { // 判断是否在搜索,如果在搜索,就取消搜索 if (mBA.isDiscovering()) { mBA.cancelDiscovery(); } try { // 获得远程设备 if (mCurDevice == null || mCurDevice != mOldDevice) { mCurDevice = mBA.getRemoteDevice(device.getAddress()); mOldDevice = mCurDevice; Log.e(TAG, "device:" + mCurDevice); // sp.edit().putString("device","device:"+mCurDevice).commit(); mSocket = mCurDevice.createRfcommSocketToServiceRecord(MY_UUID); // 连接 // mSocket.connect(); // boolean connected = mSocket.isConnected(); // if (connected){ // // // 获得输出流 // os = mSocket.getOutputStream(); // inputStream=mSocket.getInputStream(); // while (true){ // readDataFromServer(); // } // } new Thread(new Runnable() { @Override public void run() { try { mSocket.connect(); os = mSocket.getOutputStream(); mhandler.sendEmptyMessage(10); readtask = new BlueToothUtils.Readtask(); //连接成功后开启读取数据的线程 readtask.start(); mContext.getSharedPreferences("demo",Context.MODE_PRIVATE).edit().putString("device","已连接").commit(); } catch (IOException e) { mhandler.sendEmptyMessage(11); e.printStackTrace(); } } }).start(); } // 如果成功获得输出流 } catch (IOException e) { e.printStackTrace(); mhandler.sendEmptyMessage(11); } } public static final int CONNECT_FAILED=1; public static final int CONNECT_SUCCESS=5; public static final int READ_FAILED=2; public static final int WRITE_FAILED=3; public static final int DATA=4; private boolean isConnect=false; /** *开辟连接线程任务 */ public void connectTow(final BluetoothDevice device){ Thread thread = new Thread(new Runnable() { @Override public void run() { BluetoothSocket tmp = null; Method method; try { method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}); tmp = (BluetoothSocket) method.invoke(device, 1); } catch (Exception e) { // setState(CONNECT_FAILED); Log.e("TAG", e.toString()); } mSocket = tmp; try { mSocket.connect(); isConnect = true; // setState(CONNECT_SUCCESS); readtask = new BlueToothUtils.Readtask(); //连接成功后开启读取数据的线程 readtask.start(); } catch (Exception e) { Log.e("TAG", e.toString()); } } }); new Thread(thread).start(); } /** *开辟线程读任务 */ public class Readtask extends Thread{ @Override public void run(){ // byte[] buffer = new byte[9999]; // int bytes; // InputStream inputStream ; //建立输入流读取数据 // while (true) { // try { // inputStream = mSocket.getInputStream(); // if ((bytes = inputStream.read(buffer)) > 0) { // byte[] buf_data= new byte[bytes]; // for (int i = 0; i < bytes; i++) { // buf_data[i] = buffer[i]; // } // String s = new String(buf_data); // // setState(1,s); // // } // } catch (IOException e) { // // Log.e("TAG", e.toString()); // break; // } // } byte[] tt = new byte[100]; try { int ch; inputStream = mSocket.getInputStream(); int i; while (true) { synchronized (this) { i=0; while ((ch=inputStream.read())!='#'){ if (ch!=-1){ tt[i]=(byte)ch; i++; } } if (tt.length > 0) { String s = new String(tt, "GBK"); System.out.println(s); setState(1,s); }else { System.out.println(111); } } } } catch (IOException e) { e.printStackTrace(); Message message=new Message(); message.obj="连接已断开,请重新连接"; handler.sendMessage(message); } if (mSocket != null) { try { mSocket.close(); } catch (IOException e) { Log.e("TAG", e.toString()); } } } public void cancel() { try { mSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } /** *开辟线程写任务 */ public class WriteTask extends Thread{ private String srt; public WriteTask(String str){ this.srt=str; } @Override public void run(){ OutputStream outputStream=null; byte[] st=srt.getBytes(); try{ outputStream=mSocket.getOutputStream(); outputStream.write(st); }catch (Exception e){ e.printStackTrace(); } } } private void setState(int mes,String str){ Message message=new Message(); message.what=mes; message.obj=str; handler2.sendMessage(message); } /** * 传输数据 * * @param message */ public void write(String message) { try { if (os != null) { os.write(message.getBytes("GBK")); } Log.e(TAG, "write:" + message); handler2.sendEmptyMessage(3); } catch (IOException e) { e.printStackTrace(); } } /** * Stop all threads */ public synchronized void stops() { if (readtask != null) {readtask.cancel(); readtask = null;} Message message=new Message(); message.obj="关闭所有线程"; handler.sendMessage(message); } public void initSP(){ sp=mContext.getSharedPreferences("demo",Context.MODE_PRIVATE); } // 服务端,需要监听客户端的线程类 private Handler handler = new Handler() { public void handleMessage(Message msg) { showToast(String.valueOf(msg.obj)); Log.e(TAG, "服务端:" + msg.obj); super.handleMessage(msg); } }; // 线程服务类 public class AcceptThread extends Thread { private BluetoothServerSocket serverSocket; private BluetoothSocket socket; // 输入 输出流 private OutputStream os; private InputStream is; public AcceptThread() { try { serverSocket = mBA.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { // 截获客户端的蓝牙消息 try { socket = serverSocket.accept(); // 如果阻塞了,就会一直停留在这里 is = socket.getInputStream(); os = socket.getOutputStream(); while (true) { synchronized (this) { byte[] tt = new byte[is.available()]; if (tt.length > 0) { is.read(tt, 0, tt.length); Message msg = new Message(); msg.obj = new String(tt, "GBK"); Log.e(TAG, "客户端:" + msg.obj); handler.sendMessage(msg); } } } } catch (Exception e) { e.printStackTrace(); } } } }
第二个工具类
/** *建立和管理与其他设备的BT连接。 *它有一个线程来侦听传入的连接,一个线程 *用于与设备连接,以及用于执行数据的线程 *连接时的传输。 */ public class BTService { // 表示当前连接状态的常量 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; // 现在连接到远程设备 private static final String TAG = "BTConnection"; // 创建服务器套接字时SDP记录的名称 private static final String MY_NAME = "BTConnection"; //引用:[来自Android SDK文档] //如果您正在连接蓝牙串行板,则尝试使用众所周知的 //SPP UUID 000 000 110~00 0 0 0 0 0 0 0 0 0 0 0 5 5 F9B34 FB。 // 但是,如果您正在连接Android对等体,那么请生成您自己的 // ///独特的UUID。 private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 成员字段 private final BluetoothAdapter mAdapter; private final Handler mHandler; private AcceptThread mAcceptThread; private ConnectThread mConnThread; private ConnectedThread mConnectedThread; private int mState; private final Context mContext; public static BTService sInstance; /** * Constructor. Prepares a new BT session. * * @param handler A Handler to send message back to the UI Activity. * 构造函数。准备新的BT会话。 * * @param handler一个Handler,用于将消息发送回UI Activity。 */ public BTService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; mContext = context; } /** * 判断是否打开蓝牙 * * @return */ public boolean isEnabled() { if (mAdapter.isEnabled()) { return true; } return false; } /** * 搜索设备 */ public void searchDevices() { // 判断是否在搜索,如果在搜索,就取消搜索 if (mAdapter.isDiscovering()) { mAdapter.cancelDiscovery(); } // 开始搜索 mAdapter.startDiscovery(); Log.e(TAG, "正在搜索..."); } /** * 获取已经配对的设备 * * @return */ public List<BluetoothDevice> getBondedDevices() { List<BluetoothDevice> devices = new ArrayList<>(); Set<BluetoothDevice> pairedDevices = mAdapter.getBondedDevices(); // 判断是否有配对过的设备 if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { devices.add(device); Log.e(TAG, "BondedDevice:" + device.getName()); } } return devices; } /** * 与设备配对 * * @param device */ public void createBond(BluetoothDevice device) { try { Method createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } } /** * 与设备解除配对 * * @param device */ public void removeBond(BluetoothDevice device) { try { Method removeBondMethod = device.getClass().getMethod("removeBond"); removeBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } } /** * * @param device * @param str 设置PIN码 * @return */ public boolean setPin(BluetoothDevice device, String str) { try { Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class}); Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{str.getBytes()}); Log.e("returnValue", "" + returnValue); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return true; } /** * 取消用户输入 */ public boolean cancelPairingUserInput(BluetoothDevice device) { Boolean returnValue = false; try { Method createBondMethod = device.getClass().getMethod("cancelPairingUserInput"); returnValue = (Boolean) createBondMethod.invoke(device); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } // cancelBondProcess() return returnValue.booleanValue(); } /** * 取消配对 */ public boolean cancelBondProcess(BluetoothDevice device) { Boolean returnValue = null; try { Method createBondMethod = device.getClass().getMethod("cancelBondProcess"); returnValue = (Boolean) createBondMethod.invoke(device); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return returnValue.booleanValue(); } /** * @param strAddr * @param strPsw * @return */ public boolean pair(String strAddr, String strPsw) { boolean result = false; mAdapter.cancelDiscovery(); if (!mAdapter.isEnabled()) { mAdapter.enable(); } if (!BluetoothAdapter.checkBluetoothAddress(strAddr)) { // 检查蓝牙地址是否有效 Log.d("mylog", "devAdd un effient!"); } BluetoothDevice device = mAdapter.getRemoteDevice(strAddr); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { Log.d("mylog", "NOT BOND_BONDED"); try { setPin(device, strPsw); // 手机和蓝牙采集器配对 createBond(device); result = true; } catch (Exception e) { Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } // } else { Log.d("mylog", "HAS BOND_BONDED"); try { createBond(device); setPin(device, strPsw); // 手机和蓝牙采集器配对 createBond(device); result = true; } catch (Exception e) { Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } } return result; } /** * 获取device.getClass()这个类中的所有Method * * @param clsShow */ public void printAllInform(Class clsShow) { try { // 取得所有方法 Method[] hideMethod = clsShow.getMethods(); int i = 0; for (; i < hideMethod.length; i++) { Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i); } // 取得所有常量 Field[] allFields = clsShow.getFields(); for (i = 0; i < allFields.length; i++) { Log.e("Field name", allFields[i].getName()); } } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 打开蓝牙 */ public void openBlueTooth() { if (!mAdapter.isEnabled()) { // 弹出对话框提示用户是后打开 /*Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 1);*/ // 不做提示,强行打开 mAdapter.enable(); showToast("打开蓝牙"); } else { showToast("蓝牙已打开"); } } /** * 关闭蓝牙 */ public void closeBlueTooth() { mAdapter.disable(); showToast("关闭蓝牙"); } /** * 弹出Toast窗口 * * @param message */ private void showToast(String message) { if (mContext != null) { Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); } else { Log.e(TAG, "message:" + message); } } public static synchronized BTService getInstance(Context context, Handler handler) { if (sInstance == null) { sInstance = new BTService(context,handler); } return sInstance; } public BluetoothAdapter getBA() { return mAdapter; } /** * Return the current connection state. * * @return mState current connection state * 返回当前连接状态。 * * @return mState当前连接状态 */ public synchronized int getState() { return mState; } /** * Set the current state of BT connection. * * @param state An integer defining the current connection state * * *设置BT连接的当前状态。 * * @param state定义当前连接状态的整数 */ private synchronized void setState(int state) { Log.d(TAG, "setState() " + mState + "-> " + state); mState = state; // Give the new state to the Handler so the UI Activity can update //将新状态提供给处理程序,以便UI活动可以更新 mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } /** * Start the BT service. Specifically start AcceptThread to begin a * session in listening (server) mode. Called by the Activity onResume() * *启动BT服务。具体来说,启动AcceptThread以在侦听(服务器)模式下开始*会话。由Activity onResume()调用 */ public synchronized void start() { Log.d(TAG, "start"); // Cancel any thread attempting to make a connection //取消任何尝试建立连接的线程 if (mConnThread != null) { mConnThread.cancel(); mConnThread = null; } // Cancel any thread currently running a connection //取消当前正在运行连接的任何线程 if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(STATE_LISTEN); // Start the thread to listen on a BluetoothServerSocket //启动线程以侦听BluetoothServerSocket if (mAcceptThread == null) { mAcceptThread = new AcceptThread(); mAcceptThread.start(); } } /** * Start the ConnThread to initiate a connection to a remote device. *启动ConnThread以启动与远程设备的连接。 * @param device The BluetoothDevice to connect */ public synchronized void connect(BluetoothDevice device) { Log.d(TAG, "Connect to: " + device); // Cancel any thread attempting to make a connection //取消任何尝试建立连接的线程 if (mState == STATE_CONNECTING) { if (mConnThread != null) { mConnThread.cancel(); mConnThread = null; } } // Cancel any thread currently running a connection //取消当前正在运行连接的任何线程 if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // Start the thread to connect with the given device //启动线程以连接给定设备 mConnThread = new ConnectThread(device); mConnThread.start(); setState(STATE_CONNECTING); } /** * 启动ConnectedThread以开始管理蓝牙连接。 * * @param socket 连接所在的BluetoothSocket * @param device 已连接的BluetoothDevice */ public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { Log.d(TAG, "Connected"); // 取消完成连接的线程 if (mConnThread != null) { mConnThread.cancel(); mConnThread = null; } //取消当前正在运行连接的任何线程 if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } //取消接受线程,因为我们只想连接到一个设备 if (mAcceptThread != null) { mAcceptThread.cancel(); mAcceptThread = null; } //启动线程来管理连接并执行传输 mConnectedThread = new ConnectedThread(socket); mConnectedThread.start(); // 将已连接设备的名称发送回UI活动 Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(Constants.DEVICE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } /** * 停止所有线程。 */ public synchronized void stop() { Log.d(TAG, "stop"); if (mConnThread != null) { mConnThread.cancel(); mConnThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } if (mAcceptThread != null) { mAcceptThread.cancel(); mAcceptThread = null; } setState(STATE_NONE); } /** * 以不同步的方式写入ConnectedThread。 * * @param content 要写入的字节 * @see */ public void write(String content) { //创建临时对象 ConnectedThread r; //同步ConnectedThread的副本 synchronized (this) { if (mState != STATE_CONNECTED) { Log.d(TAG, "State: " + getState()); return; } r = mConnectedThread; } //执行写入不同步 r.write(content); } /** * 指示连接尝试失败并通知UI活动。 */ private void connectionError(String errMsg) { Log.e(TAG, "Connection Error:" + errMsg); // 将失败消息发送回活动 Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(Constants.TOAST, errMsg); msg.setData(bundle); mHandler.sendMessage(msg); // 启动服务以重新启动侦听模式 BTService.this.start(); } /** *此线程在侦听传入连接时运行。它表现得很好 *像服务器端客户端。它会一直运行,直到接受连接 *(或直到取消)。 */ private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { //使用稍后分配给mmServerSocket的临时对象 //因为mmServerSocket是最终的 BluetoothServerSocket tmp = null; try { tmp = mAdapter.listenUsingRfcommWithServiceRecord(MY_NAME, MY_UUID); } catch (IOException e) { Log.e(TAG, "套接字听不通", e); } mmServerSocket = tmp; } public void run() { Log.d(TAG, "套接字开始"); BluetoothSocket socket = null; // Listen to the server socket if we're not connected while (mState != STATE_CONNECTED) { try { //这是一个阻止调用,只会返回 //成功连接或异常 socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "套接字accept()失败", e); break; } //如果接受了连接 if (socket != null) { synchronized (BTService.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) { Log.e(TAG, "无法关闭不需要的套接字", e); } break; } } } } } public void cancel() { Log.d(TAG, "套接字取消"); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "服务器的套接字close()失败", e); } } } /***此线程在尝试进行传出连接时运行 *带有设备。它直接通过;连接 *成功或失败。 */ private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; //获取与之连接的BluetoothSocket //给出了BluetoothDevice try { // device.fetchUuidsWithSdp(); // ParcelUuid[] uuids = device.getUuids(); // for (ParcelUuid u : uuids) { // Log.d(TAG, u.getUuid().toString()); // } tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, "Socket create() failed", e); } mmSocket = tmp; } public void run() { try { mmSocket.connect(); } catch (IOException e) { e.printStackTrace(); try { mmSocket.close(); } catch (IOException e1) { e1.printStackTrace(); } connectionError("连接失败"); return; } //重置ConnectThread,因为我们已经完成了 synchronized (BTService.this) { mConnThread = null; } //启动连接的线程 connected(mmSocket, mmDevice); } public void cancel() { Log.d(TAG, "Socket cancel"); try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "Socket close() of server failed", e); } } } /** *此线程在与远程设备连接期间运行。 *它处理所有传入和传出传输。 */ private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; private ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; //获取BluetoothSocket输入和输出流 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() { Log.d(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[512]; byte[] ret = null; //连接时继续收听inputStream while (true) { try { //从InputStream中读取 int bytes = mmInStream.read(buffer); Log.e(TAG, "length: " + bytes); for (int i = 0; i < bytes; i++) { if ((buffer[i] & 0xFF) == 255) { ret = Arrays.copyOfRange(buffer, 0, i + 1); break; } } Log.e(TAG, "data: " + ret); //将获取的字节发送到UI活动 mHandler.obtainMessage(Constants.MESSAGE_READ, -1, -1, ret).sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); connectionError("连接失败"); //启动服务以重新启动侦听模式 BTService.this.start(); break; } } } /** * 写入已连接的OutStream。 * * @param content The bytes to write */ public void write(String content) { try { mmOutStream.write(content.getBytes()); // 将发送的消息共享回UI活动 mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, content).sendToTarget(); } catch (IOException e) { Log.e(TAG, "E写入期间的xception", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "connect()的连接套接字失败", e); } } }