Ø 藍牙的基本概念
Ø Android中藍牙的應用
能力目标
Ø 了解藍牙的基本概念
Ø 掌握Android中藍牙的應用
Ø 掌握如何使用Android中Wi-Fi
本章簡介
藍牙是一種重要的短距離無線通信技術,它被廣泛應用于各種裝置,比如計算機、手機、汽車等,支援裝置之間的近距離通信,進而是資料傳輸更加快捷有效。Wi-Fi是一種高速的無線通信協定,它具有傳輸速度高,傳輸距離長的特點。通過WiFi,手機、PDA、電腦等移動裝置可以以無線方式連接配接網絡。本節中我們主要來學習Android開發中如何調用系統中藍牙以及wifi的功能。
核心技能部分
11.1 藍牙簡介
藍牙(Bluettoth)是目前使用最廣泛的一種短距離(10M)無線通信協定之一,廣泛應用于各種裝置中,比如手機、計算機、耳機、滑鼠、鍵盤等。
藍牙采用了分散式網絡結構以及快跳頻和短包技術,支援點對點及點對多點的通信,工作在全球通用的2.4GHz頻度。根據不同的藍牙版本,傳輸速度會差很多,例如:最新的藍牙3.0傳輸速度為3Mb/s,而未來的藍牙4.0技術從理論上可達到60Mb/s。
藍牙協定分為核心協定層、電纜替代協定層、電話控制協定層、采納的其它協定層等4層,藍牙的核心協定包括基帶、鍊路管理、邏輯鍊路控制和适應協定四部分。其中鍊路管理(LMP)負責藍牙元件間連接配接的建立。邏輯鍊路控制與适應協定(L2CAP)位于基帶協定層上,屬于資料鍊路層,是一個為高層傳輸和應用層協定屏蔽基帶協定的适配協定。
藍牙技術作為目前比較常用的無線通信技術,早已經成為手機的标配之一,基于Android的手機裝置也不例外。但遺憾的是模拟器不支援藍牙程式的調試,藍牙程式必須運作在真機上,且必須是在Android版本2.0以上的真機上。
Android中藍牙有關的類和接口都位于android.bluetooth包中,如下表11-1-1所示。
表11-1-1 藍牙功能包
功能包 | 說明 |
BluetoothAdapter | 本地藍牙擴充卡 |
BluetoothClass | 藍牙類,主要包括服務和裝置 |
BluetoothClass.Device | 藍牙裝置類 |
BluetoothClass.Device.Major | 藍牙裝置管理器 |
BluetoothClass.Service | 有關藍牙的服務類 |
BluetoothDevice | 遠端藍牙裝置 |
BluetoothServerSocket | 監聽藍牙連接配接的類 |
BluetoothSocket | 藍牙連接配接類 |
這些藍牙API允許應用程式掃描、連接配接和斷開其它藍牙裝置,包括編寫和修改本地服務的SDP協定資料庫和查詢其它藍牙裝置上的SDP協定資料庫,以及在Android上建立RFCOMM協定的連接配接并連接配接到其它指定裝置上。
11.2 藍牙的打開、關閉及搜尋
通過11.1小節的學習我們知道Android中與藍牙相關的類和接口都定義在了android.bluetooth包中,我們常用的主要是BluetoothAdapter和BluetoothDevice兩個類。其中BluetoothAdapter類的對象代表了本地的藍牙擴充卡;BluetoothDevice代表了一個遠端的Bluetooth裝置。
掃描已經配對的藍牙裝置時,包括手機和電腦配對,必須得通過手動完成,不能通過代碼完成,我們應該把主要的精力放在配對完成之後的操作上來。核心步驟如下:
(1) 獲得BluetoothAdapter對象;
(2) 判斷目前裝置中是否擁有藍牙裝置;
(3) 判斷目前裝置中的藍牙裝置是否已經打開,如果沒有打開的話,要打開;
(4) 得到所有已經配對的藍牙裝置對象BluetoothDevice;
在使用藍牙之前,需要在功能清單檔案AndroidManifest.xm中添加如下權限,
<uses-permission android:name=”android.permission.BLUETOOTH”/>
<uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”/>
BluetoothAdapter是藍牙的核心類,下面的代碼建立了BluetoothAdapter對象:
adapter = BluetoothAdapter.getDefaultAdapter();
通過代碼還可以直接打開系統的藍牙設定界面,代碼如下:
Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enable, 22);
或直接使用enable()方法打開藍牙功能,代碼如下:
adapter.enable();
要關閉藍牙,可以使用如下的代碼:
adapter.disable();
藍牙裝置打開之後,還需要讓其它的藍牙裝置可以搜尋到自己,藍牙才能使用,要想讓别人能夠搜尋到自己,需要在程式中加入如下代碼:
Intent discoveryIntent =
new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(discoveryIntent,22);
每一個藍牙裝置由BluetoothDevice描述,需要定義一個List對象,來儲存搜尋到的藍牙裝置,具體代碼如下:
private List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
接着調用BluetoothAdapter的startDiscovery()方法就可以搜尋附近的藍牙裝置了。系統會在每搜尋到一個藍牙裝置時發送一個廣播,通過接收這個廣播,可以獲得搜尋到的藍牙裝置資訊。當搜尋完成時還會發送一個廣播,可以在該廣播接收器中做一些收尾工作。
示例11.1:
示範了上述藍牙的常用操作,Activity類的詳細代碼如下所示:
public class DiscoveryActivity extends ListActivity {
private Handler handler = null;
private BluetoothAdapter adapter = null;// 藍牙擴充卡對象
private List<BluetoothDevice> devices = null;// 用來存儲搜尋到的藍牙裝置
private volatile boolean discoveryFinished;// 表示搜尋是否完成
private Runnable discoveryWorkder = new Runnable() {
public void run() {
adapter.startDiscovery();// 開始搜尋
while (true) {
if (discoveryFinished) {
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
};
// 搜尋藍牙裝置時調用
private BroadcastReceiver foundReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// 獲得搜尋結果資料
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 将結果添加到裝置清單中
devices.add(device);
// 顯示清單
showDevices();
// 搜尋完成時調用
private BroadcastReceiver discoveryReceiver = new BroadcastReceiver() {
@Override
// 解除安裝注冊的接收器
unregisterReceiver(foundReceiver);
unregisterReceiver(this);
discoveryFinished = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(LayoutParams.FLAG_BLUR_BEHIND, LayoutParams.FLAG_BLUR_BEHIND);
setContentView(R.layout.discovery);
devices = new ArrayList<BluetoothDevice>();
handler = new Handler();
if (adapter != null) {
System.out.println("本機擁有藍牙裝置");
// 如果藍牙擴充卡沒有打開,則打開
if (!adapter.isEnabled()) {
// 注冊discoveryReceiver接收器
IntentFilter discoveryFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(discoveryReceiver, discoveryFilter);
// 注冊foundReceiver接收器
IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(foundReceiver, foundFilter);
// 顯示一個對話框,正在搜尋藍牙裝置
SamplesUtils.indeterminate(DiscoveryActivity.this,
handler, "正在掃描...",
discoveryWorkder,
new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
for (; adapter.isDiscovering();) {
adapter.cancelDiscovery();
}, true);
}else {
System.out.println("本機沒有藍牙裝置");
// 顯示搜尋裝置清單
protected void showDevices() {
List<String> list = new ArrayList<String>();
for (int i = 0, size = devices.size(); i < size; ++i) {
StringBuilder builder = new StringBuilder();
BluetoothDevice device = devices.get(i);
builder.append(device.getName()).append(" : ") .append(device.getAddress());
list.add(builder.toString());
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
handler.post(new Runnable() {
setListAdapter(adapter);
});
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra(BluetoothDevice.EXTRA_DEVICE, devices.get(position));
setResult(RESULT_OK, result);
finish();
将程式部署到真機上運作測試程式,結果如下圖10.1.1和圖10.1.2所示。
11.3 Wi-Fi入門
Wi-Fi的全稱是Wireless Fidelity,是一種高速的無線通信協定。Wi-Fi最大的優點是傳輸速度高,傳輸速度可以達到11M/S,另外Wi-Fi的有效傳輸距離也很長。
Wi-Fi的頻段在世界範圍内是無需任何電信營運執照就可以免費使用,是以WLAN無線裝置提供了一個世界範圍内可用的、費用極低且資料帶寬極高的無線空中接口。使用者可以在Wi-Fi覆寫區域内快速浏覽網頁、随時随地接聽、撥打電話。而其它一些基于WLAN的寬帶資料應用,如流媒體、網絡遊戲等功能更是值得使用者期待。有了Wi-Fi功能,我們打電話(包括國際長途)、浏覽網頁、收發電子郵件、音樂下載下傳、數位照片傳遞等,再也無需擔心速度慢和花費高的問題。現在Wi-Fi在國内的覆寫範圍越來越廣泛,比如進階飯店、豪華住宅區、飛機場以及咖啡廳之類的場所都有Wi-Fi接口。當我們去旅遊、辦公時,就可以在這些場所使用我們的移動裝置盡情網上沖浪了。
實際上,對于Wi-Fi并不需要過多的控制,當成功連接配接Wi-Fi後,就可以直接通過IP在Wi-Fi裝置之間進行通信了。一般隻需要控制打開或關閉Wi-Fi以及獲得一些與Wi-Fi相關的資訊,基本上來自請求端的資訊都是可見的,比如連接配接速度、IP位址、完成狀态等。不幸的是Wi-Fi功能不能在Android模拟器上測試,得使用支援Wi-Fi功能的Android真機才行,就算在有Wi-Fi功能的真機上也需要先通過Wi-Fi和其它Wi-Fi裝置連接配接後,才能獲得Wi-Fi相關的資訊。
Android中編寫Wi-Fi程式,主要涉及以下幾個類和接口。
Ø ScanResult:主要用來描述已經檢測出的接入點,包括接入點的位址、接入點的名稱、身份認證、頻率、信号強度等資訊。
Ø WifiConfiguration:Wi-Fi網絡的配置,包括安全配置等。
Ø WifiManager:提供了管理Wi-Fi連接配接的大部分API,它主要包括如下内容
(1) 已經配置好的網絡清單。這個清單可以檢視和修改,而且可以修改個别記錄的屬性。
(2) 當連接配接中有活動的Wi-Fi網絡時,可以建立或關閉這個連接配接,并且可以查詢有關網絡的狀态資訊。
(3) 對接入點的掃描結果包含足夠的資訊來決定需要與什麼接入點建立連接配接。
(4) 定義了許多常量來表示Wi-Fi狀态的改變。
Ø WifiInfo:Wi-Fi無線連接配接的描述,包括接入點、網絡連接配接狀态、隐藏的接入點、IP位址、連接配接速度、MAC位址、網絡ID、信号強度等資訊。
示例11.2
示範如何開關閉Wi-Fi以及擷取Wi-Fi相關資訊,這些資訊包括:MAC位址、接入點的BSSID、IP位址、網絡ID等。
布局檔案的詳細代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<CheckBox
android:id="@+id/chkOpenCloseWifi"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvScanResult"
android:layout_width="wrap_content"
android:id="@+id/tvWifiInfo"
android:layout_height="wrap_content"
android:textSize="20sp" />
android:id="@+id/tvWifiConfigurations"
android:layout_marginTop="20dp"
</LinearLayout>
Activity類代碼如下:
public class WIFIActivity extends Activity implements OnCheckedChangeListener {
private WifiManager manager;
private WifiInfo wifiInfo;
private CheckBox chkOpenCloseWifiBox;
private List<WifiConfiguration> wifiConfigurations;
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.wifi);
manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiInfo = manager.getConnectionInfo();
chkOpenCloseWifiBox = (CheckBox) findViewById(R.id.chkOpenCloseWifi);
TextView tvWifiConfigurations = (TextView) findViewById(R.id.tvWifiConfigurations);
TextView tvWifiInfo = (TextView) findViewById(R.id.tvWifiInfo);
chkOpenCloseWifiBox.setOnCheckedChangeListener(this);
if (manager.isWifiEnabled()) {
chkOpenCloseWifiBox.setText("Wifi已開啟");
chkOpenCloseWifiBox.setChecked(true);
} else {
chkOpenCloseWifiBox.setText("Wifi已關閉");
chkOpenCloseWifiBox.setChecked(false);
// 獲得Wifi資訊
StringBuffer sb = new StringBuffer();
sb.append("Wifi資訊\n");
sb.append("MAC位址:" + wifiInfo.getMacAddress() + "\n");
sb.append("接入點的BSSID:" + wifiInfo.getBSSID() + "\n");
sb.append("IP位址(int):" + wifiInfo.getIpAddress() + "\n");
sb.append("IP位址(Hex):" + Integer.toHexString(wifiInfo.getIpAddress()) + "\n");
sb.append("IP位址:" + ipIntToString(wifiInfo.getIpAddress()) + "\n");
sb.append("網絡ID:" + wifiInfo.getNetworkId() + "\n");
tvWifiInfo.setText(sb.toString());
// 得到配置好的網絡
wifiConfigurations = manager.getConfiguredNetworks();
tvWifiConfigurations.setText("已連接配接的無線網絡\n");
for (WifiConfiguration wifiConfiguration : wifiConfigurations) {
tvWifiConfigurations.setText(tvWifiConfigurations.getText() + wifiConfiguration.SSID + "\n");
private String ipIntToString(int ip) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (0xff & ip);
bytes[1] = (byte) ((0xff00 & ip) >> 8);
bytes[2] = (byte) ((0xff0000 & ip) >> 16);
bytes[3] = (byte) ((0xff000000 & ip) >> 24);
return Inet4Address.getByAddress(bytes).getHostAddress();
} catch (Exception e) {
return "";
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
if (isChecked) {
manager.setWifiEnabled(true);
manager.setWifiEnabled(false);
在有Wi-Fi接入點的環境中,将本程式部署到真機上進行測試,程式運作效果如下圖11.1.3所示。
任務實訓部分
1:實作一個藍牙搜尋程式
訓練技能點
利用BluetoothDevice實作藍牙裝置搜尋
需求說明
藍牙實作的功能是在兩台或多台裝置之間傳傳輸資料,是以我們要想使用藍牙裝置,首先需要能夠搜尋到對應的藍牙裝置,然後才能完成資料的傳輸。本實訓要求大家參考11.2節的内容實作一個藍牙搜尋程式,當搜尋到别的藍牙裝置後,要求以Toast的形式給使用者彈出提示資訊。
2:擷取Wi-Fi相關資訊
如何擷取Wi-Fi相關資訊
Wi-Fi的連接配接資訊在實際的應用中是很有用的,以連接配接速度為例,當我們可以在程式中根據連接配接速度的快慢做不同的工作,比如速度比較快時上傳或下載下傳資源、慢時浏覽網頁等。再比如,當我們的程式需要網絡時,可以根據Wi-Fi的完成狀态,來判斷使用者是否聯網,如果沒有聯網給使用者以相應的提示。本示例要實作的功能就是擷取Wi-Fi的所有資訊,然後顯現給使用者。
鞏固練習
一、選擇題
1. 藍牙工作的頻度是()
A. 1.8GHz
B. 2.4GHz
C. 3.2GHz
D. 3.0GHz
2. 下列說法中正确的是( )
A. WIFI的全稱是Wireless Fidelety
B. WIFI的頻段在世界範圍内是無需任何電信營運執照就可以免費使用
C. 當成功連接配接WIFI後,就可以直接通過IP在WIFI裝置之間進行通信了
D. ScanResult類主要用來描述已經檢測出的接入點
二、上機練習
編寫一程式,實作對Wi-Fi和藍牙開啟、關閉狀态的控制。