Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> Bluetooth 4.0之Android 解說

Bluetooth 4.0之Android 解說

編輯:Android編程入門

 Android平台包括了對藍牙網絡協議棧的支持,它同意一個藍牙設備跟其它的藍牙設備進行無線的數據交換。應用程序通過Android藍牙API提供訪問藍牙的功能。

這些API會把應用程序無線連接到其它的藍牙設備上,具有點到點和多點無線特征。
使用藍牙API,Android應用程序可以運行下面功能:
1.  掃描其它藍牙設備
2.  查詢本地已經配對的藍牙適配器
3.  建立RFCOMM通道
4.  通過服務發現來連接其它設備
5.  在設備間數據傳輸
6.  管理多個藍牙連接
基礎
本文介紹怎樣使用Android的藍牙API來完畢使用藍牙通信所須要的四項主要任務:設置藍牙、查找已配對或區域內可用的藍牙設備、連接設備、設備間數據傳輸。
全部的可用的API都在android.bluetooth包中。

下面概要的介紹創建藍牙連接所須要的類和接口:
BluetoothAdapter
代表本地藍牙適配器(藍牙無線)。BluetoothAdapter是全部藍牙交互的入口。

使用這個類。你可以發現其它的藍牙設備,查詢已配對設備的列表,使用已知的MAC地址來實例化一個BluetoothDevice對象,而且創建一個BluetoothServerSocket對象來監聽與其它設備的通信。
BluetoothDevice
代表一個遠程的藍牙設備。使用這個類通過BluetoothSocket或查詢諸如名稱、地址、類和配對狀態等設備信息來請求跟遠程設備的連接。
BluetoothSocket
代表藍牙socket的接口(類似TCP的Socket)。這是同意一個應用程序跟還有一個藍牙設備通過輸入流和輸出流進行數據交換的連接點。
BluetoothServerSocket
代表一個打開的監聽傳入請求的服務接口(類似於TCP的ServerSocket)。

為了連接兩個Android設備,一個設備必須用這個類打開一個服務接口。當遠程藍牙設備請求跟本設備建立連接請求時。BluetoothServerSocket會在連接被接收時返回一個被連接的BluetoothSocket對象。
BluetoothClass
描寫敘述了藍牙設備的一般性特征和功能。

這個類是一個僅僅讀的屬性集,這些屬性定義了設備的主要和次要設備類和服務。可是,這個類並不保證描寫敘述了設備所支持的全部的藍牙配置和服務,可是這樣的對設備類型的提示是故意的。
BluetoothProfile
    代表一個藍牙配置的接口。

藍牙配置是基於藍牙通信的設備間的無線接口規范。一個樣例是免提的配置。

很多其它的配置討論,請看下文的用配置來工作。
BluetoothHeadset
    提供對使用藍牙耳機的移動電話的支持。它同一時候包括了Bluetooth Headset和Hands-Free(v1.5)的配置。
BluetoothA2dp
    定義怎樣把高品質的音頻通過藍牙連接從一個設備流向還有一個設備。“A2DP”是Advanced Audio Distribution Profile的縮寫。
BluetoothHealth
    代表一個健康保健設備配置的控制藍牙服務的代理。
BluetoothHealthCallback
    用於實現BluetoothHealth回調的抽象類。

你必須繼承這個類,並實現它的回調方法,來接收應用程序的注冊狀態和藍牙通道狀態變化的更新。
BluetoothHealthAppConfiguration
    代表藍牙相關的第三方健康保健應用程序所注冊的與遠程藍牙健康保健設備進行通信的配置。


BluetoothProfile.ServiceListener
    BluetoothProfile IPCclient連接或斷開服務的通知接口(它是執行特俗配置的內部服務)。



Android的聯通性---Bluetooth(二)

藍牙權限
為了在你的應用程序中使用藍牙功能。至少要聲明兩個藍牙權限(BLUETOOTH和BLUETOOTH_ADMIN)中的一個。
為了運行不論什麼藍牙通信(如請求連接、接收連接和數據傳輸)。你必須申請BLUETOOTH權限。
為了啟動設備發現或維護藍牙設置,你必須申請BLUETOOTH_ADMIN權限。大多數需要這個權限的應用程序,不過為可以發現本地的藍牙設備。

這個權限所授予的其它能力應該不被使用。除非是電源管理的應用程序,它會在根據用戶的請求來改動藍牙設置。注意:假設你使用了BLUETOOTH_ADMIN權限,那麼必需要有BLUETOOTH權限。


在你的應用程序清單文件裡聲明藍牙權限。比如:
<manifest ... >
  <uses-permission android:name="android.permission.BLUETOOTH" />
  ...
< /manifest>
關於聲明應用程序權限的很多其它信息,請參閱<uses-permission>

設置藍牙
在應用程序可以利用藍牙通道通信之前,須要確認設備是否支持藍牙通信。假設支持,要確保它是可用的。


假設不支持藍牙,那麼你應該有好的禁用全部藍牙功能。假設支持藍牙,可是被禁用的。那麼你要在不離開你的應用程序的情況下。請求用戶啟用藍牙功能,這樣的設置要使用BluetoothAdapter對象,在下面兩個步驟中完畢。
1. 獲得BluetoothAdapter對象
BluetoothAdapter對象是全部藍牙活動都須要的。要獲得這個對象,就要調用靜態的getDefaultAdapter()方法。

這種方法會返回一個代表設備自己的藍牙適配器的BluetoothAdapter對象。

整個系統有一個藍牙適配器,你的應用程序可以使用這個對象來進行交互。

假設getDefaultAdapter()方法返回null,那麼該設備不支持藍牙,你的處理也要在此結束。比如:
BluetoothAdapter mBluetoothAdapter =BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter ==null){
// Device does not support Bluetooth
}
2. 啟用藍牙功能
接下來,你須要確保藍牙是可用的。調用isEnabled()方法來檢查當前藍牙是否可用。假設這種方法返回false。那麼藍牙是被禁用的。要申請啟用藍牙功能,就要調用帶有ACTION_REQUEST_ENABLE操作意圖的startActivityForResult()方法。它會給系統設置發一個啟用藍牙功能的請求(不終止你的應用程序)。

比如:
if(!mBluetoothAdapter.isEnabled()){
    Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
這時會顯示一個請求用戶啟用藍牙功能的對話框,如圖1所看到的:



圖1.啟用藍牙功能的對話框。
假設用戶響應“Yes”,那麼系統會開始啟用藍牙功能,完畢啟動過程(有可能失敗),焦點會返回給你的應用程序。
傳遞給startActivityForResult()方法的REQUEST_ENABLE_BT常量,是一個你的應用程序中定義的整數(它必須大於0),系統會把它作為requestCode參數返回到你的onActivityResult()回調實現中。


假設藍牙功能啟用成功,你的Activity會在onActivityResult()回調中接收到RESULT_OK結果,假設藍牙沒有被啟動(或者用戶響應了“No”),那麼該結果編碼是RESULT_CANCELED。
可選地。你的應用程序還能夠監聽ACTION_STATE_CHANGED廣播Intent。不管藍牙狀態何時改變,系統都會廣播這個Intent。這個廣播包括的附加字段EXTRA_STATE和EXTRA_PREVIOUS_STATE中分別指明了新的和舊的藍牙狀態。這些附加字段中可能的值是:STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF和STATE_OFF。監聽這個廣播對於在應用程序執行時檢測藍牙的狀態是實用的。


提示:啟用可發現能力會自己主動啟動藍牙功能。

假設你計劃在運行藍牙活動之前,要始終啟用設備的可發現機制。就能夠跳過上面的第2步,具體請參閱下文“啟用藍牙可發現”。

Android的聯通性---Bluetooth(三)

查找設備
使用BluetoothAdapter對象。可以通過設備發現或查詢已配對的設備列表來找到遠程的藍牙設備。
設備發現是一個掃描過程,該過程搜索本地區域內可用的藍牙設備,然後請求一些彼此相關的一些信息(這個過程被叫做“發現”、“查詢”或“掃描”)。可是,本地區域內的藍牙設備僅僅有在它們也啟用了可發現功能時,才會響應發現請求。假設一個設備是可發現的,那麼它會通過共享某些信息(如設備名稱、類別和唯一的MAC地址)來響應發現請求。使用這些信息,運行發現處理的設備可以有選擇的初始化跟被發現設備的連接。


一旦跟遠程的設備建立的首次連接。配對請求就會自己主動的被展現給用戶。

當設備完畢配對,相關設備的基本信息(如設備名稱、類別和MAC地址)就會被保存。並可以使用藍牙API來讀取。使用已知的遠程設備的MAC地址。在不論什麼時候都可以初始化一個連接,而不須要運行發現處理(如果設備在可連接的范圍內)。
要記住配對和連接之間的差異。配對意味著兩個設備對彼此存在性的感知。它們之間有一個共享的用於驗證的連接密鑰,用這個密鑰兩個設備之間建立被加密的連接。連接意味著當前設備間共享一個RFCOMM通道,而且可以被用於設備間的傳輸數據。當前Android藍牙API在RFCOMM連接被建立之前,要求設備之間配對。

(在使用藍牙API初始化加密連接時。配對是自己主動被運行的。


下面章節介紹怎樣發現已配對的設備,或發現新的使用了可發現功能的設備。
注意:默認Android設備是不可發現的。

用戶可以通過系統設置在限定的時間內變成可發現的設備,或者應用程序可以請求用戶啟用可發現性,而不離開應用程序。

怎樣啟用可發現性。會在下文來討論。
查詢配對設備
在運行設備發現之前。應該先查詢已配對的設備集合,來看期望的設備是否是已知的。調用getBondedDevices()方法來完畢這件工作。這種方法會返回一個代表已配對設備的BluetoothDevice對象的集合。

比如。你可以查詢全部的配對設備,然後使用一個ArrayAdapter對象把每一個已配對設備的名稱顯示給用戶。


Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if(pairedDevices.size()>0){
    // Loop through paired devices
    for(BluetoothDevice device : pairedDevices){
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName()+"\n"+ device.getAddress());
    }
}
從BluetoothDevice對象來初始化一個連接所須要的全部信息就是MAC地址。在這個樣例中。MAC地址被作為ArrayAdapter的一部分來保存,並顯示給用戶。隨後,該MAC地址可以被提取用於初始化連接。
發現設備
簡單的調用startDiscovery()方法就能夠開始發現設備。該過程是異步的。而且該方法會馬上返回一個布爾值來指明發現處理是否被成功的啟動。通常發現過程會查詢掃描大約12秒,接下來獲取掃描發現的每一個設備的藍牙名稱。
為了接收每一個被發現設備的的信息,你的應用程序必須注冊一個ACTION_FOUND類型的廣播接收器。相應每一個藍牙設備,系統都會廣播ACTION_FOUND類型的Intent。這個Intent會攜帶EXTRA_DEVICE和EXTRA_CLASS附加字段。這個兩個字段分別包括了BluetoothDevice和BluetoothClass對象。比如,下列演示了你怎樣注冊和處理設備發現時的廣播:
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // When discovery finds a device
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // Add the name and address to an array adapter to show in a ListView
            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
        }
    }
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
警告:運行設備發現,對於藍牙適配器來說是一個沉重的過程,它會消耗大量的資源。

一旦發現要連接設備,在嘗試連接之前一定要確認用cancelDiscovery()方法來終止發現操作。另外,假設已經有一個跟設備的連接,那麼運行發現會明顯的降低連接的可用帶寬,因此在有連接的時候不應該運行發現處理。



Android的聯通性---Bluetooth(四)

啟用設備的可發現性
假設要讓本地設備能夠被其它設備發現。那麼就要調用ACTION_REQUEST_DISCOVERABLE操作意圖的startActivityForResult(Intent, int)方法。這種方法會向系統設置發出一個啟用可發現模式的請求(不終止應用程序)。

默認情況下,設備的可發現模式會持續120秒。通過給Intent對象加入EXTRA_DISCOVERABLE_DURATION附加字段,能夠定義不同持續時間。

應用程序能夠設置的最大持續時間是3600秒,0意味著設備始終是可發現的。不論什麼小於0或大於3600秒的值都會自己主動的被設為120秒。比如,下面代碼把持續時間設置為300秒:
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
如圖2所看到的,申請用戶啟用設備的可發現模式時。會顯示這樣一個對話框。假設響應“Yes”。那麼設備的可發現模式會持續指定的時間,並且你的Activity會接收帶有結果代碼等於可發現設備持續時間的onActivityResult()回調方法的調用。假設用戶響應“No”或有發生錯誤。則結果代碼等於RESULT_CANCELED.
圖2.啟用可發現性對話框。
注意:假設設備沒有開啟藍牙功能,那麼開啟設備的可發現模式會自己主動開啟藍牙。
在可發現模式下,設備會靜靜的把這樣的模式保持到指定的時長。假設你想要在可發現模式被改變時獲得通知,那麼你能夠注冊一個ACTION_SCAN_MODE_CHANGED類型的Intent廣播。這個Intent對象中包括了EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE附加字段,它們會分別告訴你新舊掃描模式。它們每一個可能的值是:SCAN_MODE_CONNECTABLE_DISCOVERABLE。SCAN_MODE_CONNECTABLE或SCAN_MODE_NONE,它們分別指明設備是在可發現模式下,還是在可發現模式下但依舊可接收連接,或者是在可發現模式下並不能接收連接。


假設你要初始化跟遠程設備的連接,你不須要啟用設備的可現性。僅僅有在你想要把你的應用程序作為服務端來接收輸入連接時。才須要啟用可發現性,由於遠程設備在跟你的設備連接之前必須可以發現它。
連接設備
為了讓兩個設備上的兩個應用程序之間建立連接,你必須同一時候實現服務端和client機制,由於一個設備必須打開服務port。同一時候還有一個設備必須初始化跟服務端設備的連接(使用服務端的MAC地址來初始化一個連接)。

當服務端和client在同樣的RFCOMM通道上有一個BluetoothSocket連接時。才可以被覺得是服務端和client之間建立了連接。這時。每一個設備可以獲得輸入和輸出流。而且可以彼此開始數據傳輸。
服務端設備和client設備彼此獲取所需的BluetoothSocket的方法是不同的。服務端會在接收輸入連接的時候接收到一個BluetoothSocket對象。client會在打開跟服務端的RFCOMM通道時接收到一個BluetoothSocket對象。
一種實現技術是自己主動的准備一個設備作為服務端,以便在每一個設備都會有一個服務套接字被打開。並監聽連接請求。當還有一個設備初始化一個跟服務端套接字的連接時,它就會變成一個client。還有一種方法,一個設備是明白的”host”連接。而且依據要求打開一個服務套接字,而其它的設備僅僅是簡單的初始化連接。
注意:假設兩個設備之前沒有配對,那麼Android框架會在連接過程期間,自己主動的顯示一個配對請求通知或對話框給用戶,如圖3所看到的。因此在試圖連接設備時,你的應用程序不須要關心設備是否被配對。FRCOMM的嘗試性連接會一直堵塞,一直到用戶成功的配對。或者是因用戶拒絕配對或配對超時而失敗。

圖3.藍牙配對對話框

Android的聯通性---Bluetooth(五)
作為連接的服務端
當你想要連接兩個設備時。一個必須通過持有一個打開的BluetoothServerSocket對象來作為服務端。服務套接字的用途是監聽輸入的連接請求,而且在一個連接請求被接收時,提供一個BluetoothSocket連接對象。

在從BluetoothServerSocket對象中獲取BluetoothSocket時。BluetoothServerSocket可以(而且也應該)被廢棄。除非你想要接收很多其它的連接。

下面是建立服務套接字和接收一個連接的基本過程。


1. 調用listenUsingRfcommWithServiceRecord(String, UUID)方法來獲得一個BluetoothServerSocket對象。該方法中的String參數是一個可識別的你的服務端的名稱,系統會自己主動的把它寫入設備上的Service Discovery Protocol(SDP)數據庫實體(該名稱是隨意的,而且可以簡單的使用你的應用程序的名稱)。

UUID參數也會被包括在SDP實體中,而且是跟client設備連接的基本協議。也就是說,當client嘗試跟服務端連接時,它會攜帶一個它想要連接的服務端可以唯一識別的UUID。

僅僅有在這些UUID全然匹配的情況下,連接才可能被接收。

2. 通過調用accept()方法。啟動連接請求。

這是一個堵塞調用。僅僅有在連接被接收或發生異常的情況下,該方法才返回。僅僅有在發送連接請求的遠程設備所攜帶的UUID跟監聽服務套接字所注冊的一個UUID匹配的時候,該連接才被接收。連接成功。accept()方法會返回一個被連接的BluetoothSocket對象。

3. 除非你想要接收其它連接,否則要調用close()方法。

該方法會釋放服務套接字以及它所占用的全部資源,但不會關閉被連接的已經有accept()方法所返回的BluetoothSocket對象。

跟TCP/IP不一樣。每一個RFCOMM通道一次僅僅同意連接一個client,因此在大多數情況下。在接收到一個連接套接字之後。馬上調用BluetoothServerSocket對象的close()方法是有道理的。
accept()方法的調用不應該在主Activity的UI線程中被運行,由於該調用是堵塞的。這會阻止應用程序的其它交互。

通常在由應用程序所管理的一個新的線程中來使用BluetoothServerSocket對象或BluetoothSocket對象來工作。

要終止諸如accept()這種堵塞調用方法。就要從還有一個線程中調用BluetoothServerSocket對象(或BluetoothSocket對象)的close()方法。這時堵塞會馬上返回。

注意在BluetoothServerSocket或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(NAME, MY_UUID);
        } catch (IOException e) { }
        mmServerSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                manageConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }

    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}
在這個樣例中,僅僅希望有一個呼入連接,因此連接一旦被接收。並獲取了一個BluetoothSocket對象,應用程序就會把獲得的BluetoothSocket對象發送給一個獨立的線程。然後關閉BluetoothServerSocket對象並中斷循環。
注意。在accept()方法返回BluetoothSocket對象時,套接字已經是被連接的。因此你不應該再調用像client那樣調用connect()方法了。
應用程序中的manageConnectedSocket()方法是一個自己定義方法,它會初始化用於數據傳輸的線程。
通常,一旦你監聽完畢呼入連接,就應該關閉BluetoothServerSocket對象。在這個演示樣例中,close()方法是在獲得BluetoothSocket對象之後被調用的。你可能還想要提供一個公共方法,以便在你的線程中可以關閉你想要終止監聽的服務套接字事件中的私有BluetoothSocket對象。


作為連接的client
為了初始化一個與遠程設備(持有打開的服務套接字的設備)的連接。首先必須獲取個代表遠程設備的BluetoothDevice對象。

然後使用BluetoothDevice對象來獲取一個BluetoothSocket對象,並初始化該連接。



下面是一個主要的連接過程:
1. 通過調用BluetoothDevice的createRfcommSocketToServiceRecord(UUID)方法。獲得一個BluetoothSocket對象。

這種方法會初始化一個連接到BluetoothDevice對象的BluetoothSocket對象。傳遞給這種方法的UUID參數必須與服務端設備打開BluetoothServerSocket對象時所使用的UUID相匹配。在你的應用程序中簡單的使用硬編碼進行比對。假設匹配。服務端和client代碼就能夠應用這個BluetoothSocket對象了。



2. 通過調用connect()方法來初始化連接。在這個調用中。為了找到匹配的UUID,系統會在遠程的設備上運行一個SDP查詢。假設查詢成功,而且遠程設備接收了該連接請求。那麼它會在連接期間共享使用RFCOMM通道,而且connect()方法會返回。這種方法是一個堵塞調用。

假設由於某些原因,連接失敗或連接超時(大約在12秒之後),就會拋出一個異常。
由於connect()方法是堵塞調用,這個連接過程始終應該在獨立與主Activity線程之外的線程中被運行。
注意:在調用connect()方法時,應該始終確保設備沒有正在運行設備發現操作。假設是在發現操作的過程中。那麼連接嘗試會明顯的變慢。而且更像是要失敗的樣子。
演示樣例
下面是初始化藍牙連接線程的一個主要的樣例:
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(MY_UUID);
        } 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
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
在建立連接之前要調用cancelDiscovery()方法。在連接之前應該始終調用這種方法,而且不用實際的檢查藍牙發現處理是否正在執行也是安全的(假設想要檢查。調用isDiscovering()方法)。
manageConnectedSocket()方法是一個應用程序中自己定義的方法,它會初始化數據傳輸的線程。


當使用完BluetoothSocket對象時,要始終調用close()方法來進行清理工作。這樣做會馬上關閉被連接的套接字,並清理全部的內部資源。

Android的聯通性---Bluetooth(六)

管理連接
當你成功的連接了兩個(或很多其它)設備時。每個設備都有一個被連接的BluetoothSocket對象。這是良好的開始,由於你可以在設備之間共享數據。使用BluetoothSocket對象來傳輸隨意數據的過程是簡單的:
1. 分別通過getInputStream()和getOutputStream()方法來獲得通過套接字來處理傳輸任務的InputStream和OutputStream對象。
2. 用read(byte[])和write(byte[])方法來讀寫流中的數據。


當然,有很多其它實現細節要考慮。首先和前提,對於全部數據流的讀寫應該使用專用的線程。

這是重要的,由於read(byte[])和write(byte[])方法是堵塞式調用。

Read(byte[])方法在從數據流中讀取某些數據之前一直是堵塞的。write(byte[])方法一般是不堵塞的,可是對於流的控制。假設遠程設備不是足夠快的調用read(byte[])方法。而且中間緩存被填滿,那麼write(byte[])方法也會被堵塞。因此,你的線程中的主循環應該是專用於從InputStream對象中讀取數據。

在線程類中有一個獨立的公共方法用於初始化對OutputStream對象的寫入操作。
演示樣例
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;

        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

    /* Call this from the main activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }

    /* Call this from the main activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
上例中,構造器用於獲取必要的流對象,而且一旦被運行。線程就會等待通過InputStream對象傳入的輸入。

當read(byte[])方法從數據流中返回指定字節的數據時,使用來自其父類的Handler把該數據會被發送給主Activity,然後返回繼續等待流中的很多其它的字節。


發送輸出數據就像在主Activity中調用線程的write()方法一樣簡單,而且給該方法傳入要發送的字節。

然後這種方法簡單的調用write(byte[])方法把數據發送給遠程設備。
線程的cancel()方法是至關重要的,以便該連接在不論什麼時候可以通過關閉BluetoothSocket對象來終止。這種方法在使用完藍牙連接時應該始終被調用。


使用配置來工作
從Android3.0開始,藍牙API就包括了對用藍牙配置來進行工作的支持。Bluetooth Profile是設備之間基於藍牙進行通信的無線接口規范。

當中一個演示樣例是Hands-Free配置。

對於一個連接到無線耳機的移動電話,移動電話和藍牙耳機都必須支持Hands-Free配置。
你可以實現BluetoothProfile接口。來編寫你自己的支持特殊藍牙配置的類。Android藍牙API提供了對下面藍牙配置的實現:
· Headset(耳機):該配置提供了對用於移動電話的藍牙耳機的支持。Android提供了BluetoothHeadset類。這個類是一個代理,它通過進程間通信(IPC)來控制藍牙耳機服務。

它包括了Bluetoot Headset和Hands-Free(v1.5)配置。

BluetoothHeadset類包括了對AT命令的支持。

關於AT命令的很多其它討論,請看“Vendor-specific AT commands”。
· A2DP:Advanced Audio Distribution Profile的縮寫。

它定義怎樣流化高品質的音頻。並讓音頻流在通過藍牙連接在設備之間傳輸。Android提供了BluetoothA2dp類,它一個通過IPC來控制的藍牙A2DP服務的代理。
· Health Device:Android4.0(API Level 14)中引入了對Bluetooth Health Device Profile(HDP)的支持。

它可以讓你創建一個跟支持藍牙的健康保健設備進行藍牙通信的應用程序,這些健康保健包含:心率監護儀、血壓測量儀、體溫計、體重秤等。

相應它支持的設備的列表和它們相應的設備數據規范,藍牙聯盟的站點:www.bluetooth.org。注意,這些值也是參考了ISO/IEEE11073-20601[7]規范中命名編碼規范附件中的名為MDC_DEV_SPEC_PROFILE_*規范。
下面是使用配置進行工作的基本步驟
1. 獲取默認的適配器。
2.使用getProfileProxy()方法來建立一個與配置相匹配的配置代理對象的連接。在以下的演示樣例中。配置代理對象是一個BluetoothHeadset對象實例。
3.創建一個BluetoothProfile.ServiceListener監聽器,該監聽器會在它們連接到server或中斷與server的連接時。通知BluetoothProfile的IPCclient。


4.在onServiceConnected()事件中。獲得對配置代理對象的處理權;
5.一旦獲得配置代理對象,就能夠用它來監視連接的狀態,並運行與配置有關的其它操作。
比如,下面代碼片段顯示怎樣連接一個BluetoothHeadset代理對象。以便控制Headset配置:
BluetoothHeadset mBluetoothHeadset;

// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);

private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null;
        }
    }
};

// ... call functions on mBluetoothHeadset

// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);

Android的聯通性---Bluetooth(七)

健康設備配置
Android4.0(APILevel 14)中引入了對Bluetooth Health Device Profile(HDP)支持,這回讓你創建跟支持藍牙的健康設備進行藍牙通信的應用程序,如心率監護儀、血壓測量儀、體溫計、體重秤等。

Bluetooth Health API包括了BluetoothHealth、BluetoothHealthCallbackhe和BluetoothHealthAppConfiguration等類。
在使用的Bluetooth Health API中。有助於理解下面關鍵的HDP概念:
概念
介紹
Source
HDP中定義的一個角色,一個Source是一個把醫療數據(如體重、血彈、體溫等)傳輸給諸如Android手機或平板電腦等的設備。
Sink
HDP中定義的一個角色,在HDP中。一個Sink是一個接收醫療數據的小設備。

在一個Android HDP應用程序中。Sink用BluetoothHealthAppConfiguration對象來代表。


Registration
指的是給特定的健康設備注冊一個Sink。


Connection
指的是健康設備和Android手機或平板電腦之間打開的通信通道。
創建HDP應用程序
下面是創建Android HDP應用中所涉及到的基本步驟:
1. 獲得BluetoothHealth代理對象的引用。


類似於常規的耳機和A2DP配置設備,必須調用帶有BluetoothProfile.ServiceListener和HEALTH配置類型參數的getProfileProxy()方法來建立與配置代理對象的連接。
2. 創建BluetoothHealthCallback對象。並注冊一個扮演Health Sink角色的應用程序配(BluetoothHealthAppConfiguration)。
3. 建立跟健康設備的連接。某些設備會初始化連接,在這種設備中進行這一個步是沒有必要的。
4. 當成功的連接到健康設備時,就能夠使用文件描寫敘述來讀寫健康設備。所接收到的數據須要使用健康管理器來解釋。這個管理器實現了IEEE 11073-xxxxx規范。


5. 完畢以上步驟後。關閉健康通道,並注銷應用程序。

該通道在長期被閒置時,也會被關閉。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved