Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 藍牙串口服務客戶端開發 嘗試

Android 藍牙串口服務客戶端開發 嘗試

編輯:關於Android編程

如題,經過三四天的開發嘗試已經初步成型,下面是簡陋的界面圖:

\\

上圖是做的藍牙串口服務的收發界面,主要用於平時的調試之用,由於開發的初衷是為了實現藍牙對單片機的控制,因此加入了<進入控制/>的按鈕選項,下圖是控制界(xian)面(tiao)

\

沒辦法,沒有太多的美學細胞,拖了兩個重寫的seekbar就作為控制搖桿了。。。

初次寫Android,初次觸及Java,水平自然就是無言以對,哈哈,不過為了防止萬一以後有需求的升級,博客還是要寫的。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPGgxPjxzdHJvbmc+MS67t76ztO69qDwvc3Ryb25nPjwvaDE+CjxwPkFuZHJvaWS/qrei1d+52c34yc/M4bmpwcvBvczXvK+zyb+qt6K7t76zo6xFY2xpcHNlJiM0MztBRFS6zUFuZHJvaWQgc3R1ZGlvo6zDu9PQtuDP677Nz8LBy7j2RWNsaXBzZSYjNDM7QURUo6ywstewuvPUy9DQyrG7ucrHs/bBy7XjzsrM4qOszOHKvkZhaWxlZCB0byBjcmVhdGUgdGhlIGphdmEgdml0dWFsIG1hY2hpbmUsusOwydXiuPbOyszizfjJz9K7y9HSu7TzsNGjrLTztdbLtcrHxNq05s7KzOKjrNa70Oiw0WVjbGlwc2UuaW5pxeTWw87EvP7P4LnYxNq05rLOyv2199Cho6y7+bG+vs3Du8qyw7TOysziwcuhozwvcD4KPGgxPjIutLS9qLXa0ru49kFQUDwvaDE+CjxwPrrDwcvPwsPmu/mxvsrHv7/XxbnZzfi1xHRyYWluaW5nssTBz7+qyry1xLXa0ru49mFwcLOiytSjrNfF1tjLtdK7z8K0tL2oYW5kcm9pZLmks8y1xLy4uPbRoc/utcTS4tLlo6y808nuz8K8x9Lko7o8L3A+CjxwPlByb2plY3QgTmFtZTq5pLPMtcTEv8K8w/u6zb+qt6K7t76z1tC1xMP719Y8L3A+CjxwPlBhY2thZ2UgTmFtZTrTptPDs8zQ8rXEw/zD+7/VvOSjrLWrysfSqrGj1qSyu8TczazT2rCy17/Ptc2z1tDG5Mv7cGFja2FnZbXEw/vX1qOsxKzIz8rHY29tLmV4YW1wbGUuYXBwbmFtZTwvcD4KPHA+TWluaW11bSBSZXF1aXJlZCBTREs61ri2qNOm08OzzNDyxNzWp7PWtcTX7rXNsLLXv7Dmsb6jqEFQSQogTEVWRUyjqaOs1+66w8rHvauw5rG+yejOqtfutc2jqMq508PErMjPvLS/yaOpo6zV4tH5v8nS1MjDxOO1xGFwcMzhuam6y9DEzNjV96OstvjI57n7xOO1xGFwcMDvsdjQ6NKq08O1vdTauPy437Dmsb6wste/yc+yxdPQtcTM2NX3sqLH0rTLzNjV97KisrvTsM/sxOO1xLrL0MTM2NX3o6zEx8O0v8nS1Na71Nq437Dmsb61xLCy17/Gvcyo1tCyxcq5xNy4w8zY1fc8YnI+CjwvcD4KPHA+VGFyZ2V0CiBTREujurHtw/fE47XEYXBwv8nE3LXE1+6437Cy17+w5rG+tcSy4srUxr3MqKOoYXBpIGxldmVso6ks1eLKx7P209phbmRyb2lksOaxvrj80MK1xL+8wsejrM6qwcvE3Lm7yMPTw7uns8zQ8salxeTX7tDCtcRhcGm907/aPGJyPgo8L3A+CjxwPkNvbXBpbGUKIFdpdGijutXiysfE47XE06bTw7PM0PK9q9KqyrnTw7XEseDS68a9zKijrMixyqHH6b/2z8LKx9Gh1PHX7tDCsOaxvqOstbHIu8Tjv8nS1NGh1PG1zbDmsb6jrLWrysfQwrDmsb6/ydLUyMPE47XE06bTw7PM0PLKudPD0MK1xMzY1feyosfS08W7r7XEs8zQ8r/J0tSy+sn6uPy6w7XE08O7p8zl0ek8YnI+CjwvcD4KPHA+VGhlbWWjutb3zOKjrFVJtcS35yYjMjY2ODQ7z+C52LXEo6zI52FjdGlvbmJhcjxicj4KPC9wPgo8cD66w8HLo6zV4tCp0aHU8cHLo6zPwsPmyLHKob7Nv8nS1KOsYmxhbmsKIGFjdGl2aXR5xKzIz8rH0ru49mhlbGxvIHdvcmxks8zQ8qGjPC9wPgo8cD7PwsPm1NnXxdbYy7XPwmFuZHJvaWQKIHByb2plY3S1xM7EvP7X6davveG5uaOoztLE3NPDtb21xKOpo7o8L3A+CjxwPkFuZHJvaWRNYW5pZmVzdC54bWw8YnI+CjwvcD4KPHA+ILmks8y4+cS/wrzPwrHIvc/W2NKqtcTOxLz+o6zD6Mr206bTw7PM0PK1xLv5sb7M2NX3us3X6bz+o6y089bCyOfPwgogo7o8YnI+CjwvcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;"> /src:

src文件下自然就是源文件了,是以package來組織的,com.example.appname,也就是我們的應用程序的package下,有幾個activity應該就有幾個對應的源文件(不知道准確不?)

/res

這個文件夾就是資源文件夾,包含有drawable-hdpi,layout,menu,values等文件夾,drawable-hdpi 包含繪圖性質的對象,如bitmap,hdpi是指針對高密度的顯示屏,當然其實還有其他不同密度屏幕對應的文件夾,layout也就是界面布局,也是用xml文件組織, menu?。。。上圖

\

value 多用來定義應用程序中的常量資源,如string,color等。

3.運行程序

我是用手機直接運行的,很簡單打開手機的usb調試,然後點擊運行,確定設備,程序就會部署到手機並運行,並且通過logcat可以實時輸出調試信息,追蹤程序運行。

4.藍牙

好了,了解基本開發步驟後,可以開始嘗試藍牙的開發,依然緊跟開發者官網,找到api guides->connnectivity->bluetooth。傳說中藍牙4.0支持BLE技術,不過下文只是傳統的藍牙開發。在正式的開發之前,官網先向我們拋出了如下幾個概念:

BluetoothAdapter:

所有藍牙交互的入口點,通過它,你可以發現其他藍牙設備,訪問綁定的藍牙設備,並且可以通過MAC地址實例化一個BluetooothDevice以及創建bluetoothserversocket來監聽待接入的設備。

BluetoothDevice:

表示一個遠程的藍牙設備,用它你可以通過BluetoothSocket 來申請與遠程藍牙設備的連接,當然你也可以通過它來訪問設備名稱,地址,綁定狀態等

BluetoothSocket:

表示藍牙套接字的接口,通過InputStream和OutputStream可實現與遠程藍牙設備的數據交換

BluetoothServerSocket:

表示一個開放的服務端套接字用來監聽外部的申請,為了實現兩個藍牙設備的通信,必須有一端開放服務套接字來讓遠程設備請求連接,當遠程設備的請求被允許時,那麼就會返回一個連接的BluetoothSocket

BluetoothClass:

描述了一個藍牙設備的通用特性和能力,它是一組只讀的特性用來定義設備的主要和次要設備類以及它的服務

下面還有諸如BluetoothProfile,BluetoothHeadset等這樣的一些概念,但是由於本應用中不涉及,故不一一介紹。好了在正式藍牙開發步驟之前,有一點是不容忽視的,那就是藍牙的操作權限

    
    
上面兩條代碼是必須要加入到AndroidManifest.xml文件中的,第一條是使用藍牙特性的權限如:申請連接,接受連接和傳輸數據,而第二條則主要是用來發現周圍的藍牙設備權限。好了,這樣我們便可以開始肆無忌憚的藍牙操作了。

4.1建立本地藍牙

首先是通過getDefaultAdapter()來獲得BluetoothAdapter,BluetoothAdapter 代表本地藍牙的接收器,並且整個系統中有且只能有一個Adapter ,如果你的設備不支持藍牙設備,則函數會返回 NULL

如果設備支持藍牙,那麼接下來該是使能藍牙設備,調用isEnabled() 函數來判斷藍牙是否被使能(也就是打開),如果返回false那麼要通過startActivityForResult() 來申請藍牙的打開:

if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, 1);
}
Intent是安卓的一種運行時綁定機制,在程序運行過程中連接兩個不同的組件,這裡是向系統申請開啟藍牙意願,安卓根據相應意願開啟一個Activity,如下圖所示:
\

4.2尋找藍牙設備

通過BluetoothAdapter就可以發現遠程設備或者訪問已配對的設備,這裡解釋一下發現遠程設備和訪問已配對設備的區別,所謂發現遠程設備是指對附近可被發現的藍牙設備進行搜索並獲取相應信息(如名字,MAC等);而訪問已配對的設備則是指表示某些藍牙設備的信息(名字,MAC)已經被存入本地,那麼如果這些藍牙設備在范圍並且打開,那麼只要使用MAC地址直接與設備連接,而無需發現查找這一步驟。

在因為真正發現設備步驟之前,訪問已經配對的設備是有必要的,因為可能你需要的設備已經在配對列表中,Android系統中只要調用 getBondedDevices()函數就可以獲得一系列綁定的BluetoothDevice,而發現藍牙設備的操作也是很簡單的,調用startDiscovery(),這個函數不過是一個搜索過程的啟動按鈕,並且會立刻返回是否正常啟動搜索信息,那麼接下來將是大約12S左右的藍牙搜索過程,這裡需要注意的是我們需要在程序中注冊Broadcast Receiver組件,因為系統在每搜索到一個藍牙設備後會通過ACTION_FOUND Intent來通知,並且攜帶EXTRA_DEVICEEXTRA_CLASS信息,這裡Broadcast Receiver注冊與實現形如下:

// 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


4.3連接藍牙設備

因為本人應用場合是主動去連接藍牙設備,所以這裡主要是實現以客戶端連接步驟,在4.2節我們已經講到了如何找到設備並獲得 BluetoothDevice,那麼現在就是利用 BluetoothDevice來連接遠程設備(open server socket),這裡通過BluetoothDevice的 createRfcommSocketToServiceRecord(UUID)來實現獲得 BluetoothSocket,那麼下面便是連接了,不過別忘了在連接之前要將發現設備過程關閉,因為該過程浪費資源很多會造成連接緩慢甚至是失敗,調用cancelDiscovery();連接藍牙設備則是調用BluetoothSocket的connect() 實現,如果UUID及對方設備都已接受應該就能連接成功,不過該連接函數是個阻塞函數,所以為了避免用戶窗口的阻塞,一般將其放入單獨的一個線程,示例代碼如下 :

tip:UUID(Universally Unique Identifier),這裡主要用該參數來申請連接特殊的藍牙服務,如我申請的藍牙串口那麼就是

device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

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) { }
    }
}

4.4管理藍牙連接

你一定注意到了上代碼中的

manageConnectedSocket(mmSocket);

這樣一句,這其實才是真正的重點,同樣作為一個單獨的線程,主要負責管理藍牙數據的收發,這裡主要通過藍牙套接字獲得數據的輸入輸出流,然後根據相應流接口對藍牙進行讀寫操作:

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) { }
    }
}
好了整個藍牙打開及管理的基本步驟,界面設計及交互就沒什麼好說的了,不過要提一下在開發過程中遇到了幾個問題或建議吧:

1.Android是不能在線程中更新UI的,必須通過Handler來實現信息的傳遞更新

2.setRequestedOrientation函數可以改變界面的顯示方向,但是要注意的是該函數會引起Activity的onCreate調用,也就是UI或組件會被重新創建,為了避免可以重寫

onConfigurationChanged而後根據this.getResources().getConfiguration().orientation 來執行相應操作

3.可以適當重寫控件工具包的實現來達到想要的UI效果

4.CTRL+SHIFT+O神KEY



參考:http://developer.android.com/guide/topics/connectivity/bluetooth.html#ManagingAConnection


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