Android蓝牙高级操作(多连接)

  最近一直在做与bluetooth相关的应用。主要涉及android手机蓝牙的多连接问题。网上几乎没有与蓝牙多连接相关的具体实现资料,所以我开始从android的官方文档入手,大半夜的一个人坐下面看那英文文档,真TMD不是滋味,现在回想下当年做的英语阅读理解真似一坨shit。不过功夫不负有心人,终于搞清楚了它的构架和通信模式。这里我先讲bluetooth的基本操作,然后再深入讲解它的多连接问题(大家期待的重头戏)。注意:我这里主要讲的是多连接的核心实现,至于蓝牙的一些基础操作,我只是简单的介绍。如果有不懂的可以参考其他资料。我也做了一个测试Demo,里面的代码基本参考的官方文档,若有疑问可以去官网上看看。我试过一次可以连接三个手机。当然这不一定是极限数据,因为设备有限。有条件的朋友可以修改下代码,做下压力测试。

Demo代码下载:http://download.csdn.net/detail/wangwang6233/7188881

官方文档:http://developer.android.com/guide/topics/connectivity/bluetooth.html

参考博客:http://zhouyunan2010.iteye.com/blog/1186021

流程:

(1)蓝牙的介绍,相关API使用说明,使用蓝牙的准备工作。

(2)蓝牙的开启和关闭。

(3)设置设备可被搜索。

(4)搜索设备及广播接收器的注册。

(5)蓝牙的配对。

(6)蓝牙的连接服务端和客户端

(7)蓝牙的多连接操作。

讲解:

(1)蓝牙的介绍,相关API使用说明,使用蓝牙的准备工作。

        蓝牙,是一种支持设备短距离通信(一般10m内)的无线电技术。理论上一个蓝牙设备可以连接7个蓝牙设备(我没试过,只是理论上)。首先可行性是没问题的。其他蓝牙信息我就不阐述了,大家问度娘吧!在android app上使用bluetooth时需在AndroidManifest.xml中加上权限:

<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" /> 
      <uses-permissionandroid:name="android.permission.BLUETOOTH" /> 

我简单说下相关的API类,和常用的方法。

BluetoothAdapter:顾名思义,蓝牙适配器,蓝牙的打开、关闭、搜索都和它有关BluetoothAdapter.getDefaultAdapter()获取。

BluetoothDevice:看名字就知道,这个类是描述一个蓝牙设备,从它可以获取蓝牙的地址和设备名getAddress(),getName()。并且蓝牙设备有三种状态BOND_BONDEDBOND_BONDINGBOND_NONE分别是已绑定,绑定中、未绑定。

BluetoothServerSocket:这是服务端,通过accept()返回BluetoothSocket。既然是Socket相信大家都再熟悉不过了吧!如果你不太清楚socket编程,那就先去看java基础吧!这里我也不能偏题。

BluetoothSocket:这是客户端,connect()与服务端进行连接。通过它回去输入输出流。

(2)蓝牙的开启和关闭。

打开蓝牙:

private void startBluetooth() {
		if (mBluetoothAdapter == null) {
			// 表明此手机不支持蓝牙
			Log.d(TAG, "device is not supported bluebooth");
			return;
		}
		if (!mBluetoothAdapter.isEnabled()) { // 蓝牙未开启,则开启蓝牙
			mBluetoothAdapter.enable();
		}
	}
关闭蓝牙:

if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
					mBluetoothAdapter.disable();
				}
(3) 设置设备可被搜索。
// 使本机蓝牙在300秒内可被搜索
	private void ensureDiscoverable() {
		if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
			Intent discoverableIntent = new Intent(
					BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
			discoverableIntent.putExtra(
					BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//设置被发现时间
			startActivity(discoverableIntent);
		}
	}
(4) 搜索设备及广播接收器的注册。

记得在onCreate()中注册,在onDestory()中unregisterReceiver(searchDevices);这是android广播机制的基础,不懂的可以回去看看android广播基础了。

private void register2Broadcast() {
		IntentFilter intent = new IntentFilter();
		intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果
		intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
		intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
		intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
		registerReceiver(searchDevices, intent);
	}

	private BroadcastReceiver searchDevices = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			String action = intent.getAction();
			if (BluetoothDevice.ACTION_FOUND.equals(action)) {
				BluetoothDevice device = intent
						.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				//addDevice2List(device); 获取BluetoothDevice后剩下的自己处理了 
			}
		}
	};
(5)蓝牙的配对。

这里我们用到的是java的反射机制。

private void paireDevice(BluetoothDevice device) {
		try {
			Method createBondMethod = BluetoothDevice.class
					.getMethod("createBond");
			createBondMethod.invoke(device);
		} catch (Exception e) {
			// TODO: handle exception
			e.getStackTrace();
		}
	}
(6)蓝牙的连接服务端和客户端

服务端:这里我声明了四个BluetoothSocket。因为accept()是阻塞操作,一旦连接成功就会返回BluetoothSocket,然后继续等待下一个连接。如此下去我们就实现了多连接。UUID是作为服务端的标识。获得BluetoothSocket后,我们就可以进行相关的操作了,获取输入输出流。进行相互的通信。

private class AcceptThread extends Thread {
		private final BluetoothServerSocket mmServerSocket;

		public AcceptThread() {
			// Use a temporary object that is later assigned to mmServerSocket,
			// because mmServerSocket is final
			BluetoothServerSocket tmp = null;
			try {
				// MY_UUID is the app's UUID string, also used by the client
				// code
				tmp = mBluetoothAdapter
						.listenUsingRfcommWithServiceRecord(
								"eric",
								UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
			} catch (IOException e) {
			}
			mmServerSocket = tmp;
		}

		public void run() {
			// Keep listening until exception occurs or a socket is returned
			while (true) {
				try {
					Log.d(TAG, "thread is start and accept");
					if (socket == null) {
						socket = mmServerSocket.accept();
						Log.d(TAG, "accept ok");
						
						// If a connection was accepted
						if (socket != null) {
							// Do work to manage the connection (in a separate
							// thread)
							Log.d(TAG, "manageConnectedSocket");
							manageConnectedSocket(socket);//相关处理函数
							// break;
						}
					}
					if (socket_two == null) {
						Log.d(TAG, "wait two");
						socket_two = mmServerSocket.accept();
						Log.d(TAG, "accept ok");
						// If a connection was accepted
						if (socket != null) {
							// Do work to manage the connection (in a separate
							// thread)
							Log.d(TAG, "manageConnectedSocket");
							manageConnectedSocket(socket_two);
						}
					}
					if (socket_three == null) {
						socket_three = mmServerSocket.accept();
						Log.d(TAG, "accept ok");
						// If a connection was accepted
						if (socket != null) {
							// Do work to manage the connection (in a separate
							// thread)
							Log.d(TAG, "manageConnectedSocket");
							manageConnectedSocket(socket_three);
						}
					}
					if (socket_four == null) {
						socket_four = mmServerSocket.accept();
						Log.d(TAG, "accept ok");
						// If a connection was accepted
						if (socket != null) {
							// Do work to manage the connection (in a separate
							// thread)
							Log.d(TAG, "manageConnectedSocket");
							manageConnectedSocket(socket_four);
							break;
						}
					}
				} catch (IOException e) {
					break;
				}

			}
		}

		/** Will cancel the listening socket, and cause the thread to finish */
		public void cancel() {
			try {
				mmServerSocket.close();
			} catch (IOException e) {
			}
		}

		private void manageConnectedSocket(BluetoothSocket socket) {
			if (socket!=null) {
				readThread read = new readThread(socket);
				read.start();
			} 
		}
	}
客户端:其中的UUID要与服务端的UUID相对应。同理connect()也是阻塞操作。连接成功后即返回BluetoothSocket。
private class ConnectThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final BluetoothDevice mmDevice;

		public ConnectThread(BluetoothDevice device) {
			// Use a temporary object that is later assigned to mmSocket,
			// because mmSocket is final
			BluetoothSocket tmp = null;
			mmDevice = device;

			// Get a BluetoothSocket to connect with the given BluetoothDevice
			try {
				// MY_UUID is the app's UUID string, also used by the server
				// code
				tmp = device.createRfcommSocketToServiceRecord(UUID
						.fromString("00001101-0000-1000-8000-00805F9B34FB"));
			} catch (IOException e) {
			}
			mmSocket = tmp;
		}

		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
				Log.d(TAG, "thread is start and connect");
				mmSocket.connect();
				Log.d(TAG, "connect ok");
				Message msg=mHandler.obtainMessage();
				msg.what=3;
				msg.sendToTarget();
			} catch (IOException connectException) {
				// Unable to connect; close the socket and get out
				Log.d(TAG, "connect throw expection");
				try {
					mmSocket.close();
				} catch (IOException closeException) {
				}
				return;
			}

			// Do work to manage the connection (in a separate thread)
			socket=mmSocket;
			if(socket!=null){
				manageConnectedSocket(socket);
			}
		}

		/** Will cancel an in-progress connection, and close the socket */
		public void cancel() {
			try {
				socket.close();
			} catch (IOException e) {
			}
		}

		private void manageConnectedSocket(BluetoothSocket socket) {
			readThread read = new readThread(socket)//开启读取数据线程;
			read.start();
			Log.d(TAG, "the read is start");
		}
	}
数据读入代码:这里我们另起一个线程,当有输入流时就进行获取。这里我们与Handler一起使用,这样就可以在界面及时更新数据。
// 读取数据
	private class readThread extends Thread {
		private BluetoothSocket socket;

		public readThread(BluetoothSocket socket) {
			this.socket = socket;
		}

		public void run() {

			byte[] buffer = new byte[1024];
			int bytes;
			InputStream mmInStream = null;
			try {
				mmInStream = this.socket.getInputStream();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			while (flag) {
				try {
					Log.d(TAG, "get inputstream");
					// Read from the InputStream
					if ((bytes = mmInStream.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);
						Log.d(TAG, s);
						Message msg = new Message();
						msg.what = 2;
						msg.obj = s;
						mHandler.sendMessage(msg);
					}
				} catch (IOException e) {
					try {
						mmInStream.close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					break;
				}
			}
		}
	}
发送数据(写入输出流)

这里可能有人不懂为什么这么麻烦。我这写的是服务端群发数据。所有有连接的客户端都能收到。

private void sendMessage(){
		String s = ed_message.getText().toString()+"";
		if (socket == null) {
			Log.d(TAG, "socket is not connect");
		} else {
			try {
				OutputStream os = socket.getOutputStream();
				os.write(s.getBytes());
				Log.d(TAG, "write to outputstream success,socket");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		if (socket_two == null) {
			Log.d(TAG, "socket_two is not connect");
		} else {
			try {
				OutputStream os = socket_two.getOutputStream();
				os.write(s.getBytes());
				Log.d(TAG, "write to outputstream success,socket_two");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (socket_three == null) {
			Log.d(TAG, "socket_three is not connect");
		} else {
			try {
				OutputStream os = socket_three.getOutputStream();
				os.write(s.getBytes());
				Log.d(TAG, "write to outputstream success,socket_three");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (socket_four == null) {
			Log.d(TAG, "socket_four is not connect");
		} else {
			try {
				OutputStream os = socket_four.getOutputStream();
				os.write(s.getBytes());
				Log.d(TAG, "write to outputstream success,socket_four");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
(7)蓝牙的多连接操作。

代码已在(6)中贴出来了,这里我就解释一下,这里所谓的多连接就是一个服务端和多个客户端。重点就是在服务端一个accept()成功获取BluetoothSocket后,我们要继续监听下一个BluetoothSocket,就像我为什么声明了四个BluetoothSocket(socket,socket_two,socket_three,socket_four);其实没有什么技巧,只要你熟悉socket编程。多试试就OK了。大家可以下载测试Demo进行多次调试。多看看就懂了,而且我的代码还有许多可以改进的地方,大家可以互相讨论学习,路总是人走出来了,如果总吃现成的就永远得不到创新。我这里仅仅做个启发。

Demo代码下载:http://download.csdn.net/detail/wangwang6233/7188881












猜你喜欢

转载自blog.csdn.net/wangwang6233/article/details/23564627
今日推荐