Android藍芽高階操作(多連線)
最近一直在做與bluetooth相關的應用。主要涉及Android手機藍芽的多連線問題。網上幾乎沒有與藍芽多連線相關的具體實現資料,所以我開始從android的官方文件入手,大半夜的一個人坐下面看那英文文件,真TMD不是滋味,現在回想下當年做的英語閱讀理解真似一坨shit。不過功夫不負有心人,終於搞清楚了它的構架和通訊模式。這裡我先講bluetooth的基本操作,然後再深入講解它的多連線問題(大家期待的重頭戲)。注意:我這裡主要講的是多連線的核心實現,至於藍芽的一些基礎操作,我只是簡單的介紹。如果有不懂的可以參考其他資料。我也做了一個測試Demo,裡面的程式碼基本參考的官方文件,若有疑問可以去官網上看看。我試過一次可以連線三個手機。當然這不一定是極限資料,因為裝置有限。有條件的朋友可以修改下程式碼,做下壓力測試。
流程:
(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()。並且藍芽裝置有三種狀態
BluetoothServerSocket:這是服務端,通過accept()返回BluetoothSocket。既然是Socket相信大家都再熟悉不過了吧!如果你不太清楚socket程式設計,那就先去看Java基礎吧!這裡我也不能偏題。
BluetoothSocket:這是客戶端,connect()與服務端進行連線。通過它回去輸入輸出流。
(2)藍芽的開啟和關閉。
開啟藍芽:
- privatevoid 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();
- }
- // 使本機藍芽在300秒內可被搜尋
- privatevoid 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);
- }
- }
記得在onCreate()中註冊,在onDestory()中unregisterReceiver(searchDevices);這是android廣播機制的基礎,不懂的可以回去看看android廣播基礎了。
- privatevoid 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
- publicvoid 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後剩下的自己處理了
- }
- }
- };
這裡我們用到的是java的反射機制。
- privatevoid paireDevice(BluetoothDevice device) {
- try {
- Method createBondMethod = BluetoothDevice.class
- .getMethod("createBond");
- createBondMethod.invoke(device);
- } catch (Exception e) {
- // TODO: handle exception
- e.getStackTrace();
- }
- }
服務端:這裡我聲明瞭四個BluetoothSocket。因為accept()是阻塞操作,一旦連線成功就會返回BluetoothSocket,然後繼續等待下一個連線。如此下去我們就實現了多連線。UUID是作為服務端的標識。獲得BluetoothSocket後,我們就可以進行相關的操作了,獲取輸入輸出流。進行相互的通訊。
- privateclass AcceptThread extends Thread {
- privatefinal 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;
- }
- publicvoid 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) {