android藍(lán)牙入門知識(shí)和優(yōu)秀藍(lán)牙第三方庫BluetoothKit的使用

???這篇博客的作用是為了讓小白朋友了解andorid藍(lán)牙的一些基本概念,同時(shí)學(xué)習(xí)總結(jié)下目前我實(shí)際項(xiàng)目中用到的藍(lán)牙庫 BluetoothKit ,包括其優(yōu)點(diǎn) 霹肝、基本使用位仁,最后以庫中的源碼為基石深入探究這個(gè)優(yōu)秀的藍(lán)牙庫的設(shè)計(jì)理念痴晦。
???

一 . 藍(lán)牙基礎(chǔ)知識(shí):

1宙地、BLE藍(lán)牙的基本介紹

1.1BLe藍(lán)牙介紹

Android 4.3(API Level 18)開始引入Bluetooth Low Energy(BLE像鸡,低功耗藍(lán)牙)的核心功能并提供了相應(yīng)的 API, 應(yīng)用程序通過這些 API 掃描藍(lán)牙設(shè)備分冈、查詢 services、讀寫設(shè)備的 characteristics(屬性特征)等操作霸株。

Android BLE 使用的藍(lán)牙協(xié)議是 GATT 協(xié)議雕沉,有關(guān)該協(xié)議的詳細(xì)內(nèi)容可以參見藍(lán)牙官方文檔或者這篇博客(https://blog.csdn.net/u013378580/article/details/52891462)。以下我引用一張官網(wǎng)的圖來大概說明 Android 開發(fā)中我們 用到的一些專業(yè)術(shù)語去件。(專業(yè)名詞參考1.2節(jié)內(nèi)容)

藍(lán)牙協(xié)議圖.png

1.2坡椒、Android BLE的相關(guān)系統(tǒng)API

Profile

一個(gè)通用的規(guī)范,即Ble的藍(lán)牙通訊協(xié)議尤溜,Ble藍(lán)牙的必須按照這個(gè)規(guī)范來收發(fā)數(shù)據(jù)倔叼。

Service

一個(gè)低功耗藍(lán)牙設(shè)備可以定義許多 Service, Service 可以理解為一個(gè)功能的集合。設(shè)備中每一個(gè)不同的 Service 都有一個(gè) 128 bit 的 UUID 作為這個(gè) Service 的獨(dú)立標(biāo)志宫莱。藍(lán)牙核心規(guī)范制定了兩種不同的UUID丈攒,一種是基本的UUID,一種是代替基本UUID的16位UUID授霸。所有的藍(lán)牙技術(shù)聯(lián)盟定義UUID共用了一個(gè)基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB 為了進(jìn)一步簡化基本UUID巡验,每一個(gè)藍(lán)牙技術(shù)聯(lián)盟定義的屬性有一個(gè)唯一的16位UUID,以代替上面的基本UUID的‘x’部分碘耳。例如显设,心率測(cè)量特性使用0X2A37作為它的16位UUID,因此它完整的128位UUID為: 0x00002A37-0000-1000-8000-00805F9B34FB

BluetoothAdapter

BluetoothAdapter 擁有系統(tǒng)調(diào)用藍(lán)牙基本的藍(lán)牙操作辛辨,例如開啟藍(lán)牙掃描 連接捕捂,使用已知的 MAC 地址 (BluetoothAdapter#getRemoteDevice)實(shí)例化一個(gè) BluetoothDevice 用于連接藍(lán)牙設(shè)備的操作等等。

BluetoothDevice

代表一個(gè)遠(yuǎn)程藍(lán)牙設(shè)備愉阎。這個(gè)類可以讓你連接所代表的藍(lán)牙設(shè)備或者獲取一些有關(guān)它的信息绞蹦,例如它的名字,地址和綁定狀態(tài)等等榜旦。

RSSI

Received Signal Strength Indication.用來標(biāo)識(shí)搜索到的設(shè)備的信號(hào)強(qiáng)度值幽七。

BluetoothGatt

這個(gè)類提供了 Bluetooth GATT 的基本功能。例如重新連接藍(lán)牙設(shè)備溅呢,發(fā)現(xiàn)藍(lán)牙設(shè)備的 Service 等等澡屡,是在一個(gè)中心設(shè)備(如手機(jī))和外圍設(shè)備(手環(huán)等Ble設(shè)備)之間建立的數(shù)據(jù)通道,通過調(diào)用gatt對(duì)象的一系列方法來操作藍(lán)牙咐旧。

UUID

一個(gè)service對(duì)應(yīng)一個(gè)UUID

一藍(lán)牙核心規(guī)范制定了兩種不同的UUID驶鹉,一種是基本的UUID,一種是代替基本UUID的16位UUID铣墨。所有的藍(lán)牙技術(shù)聯(lián)盟定義UUID共用了一個(gè)基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB

為了進(jìn)一步簡化基本UUID室埋,每一個(gè)藍(lán)牙技術(shù)聯(lián)盟定義的屬性有一個(gè)唯一的16位UUID,以代替上面的基本UUID的‘x’部分。例如姚淆,心率測(cè)量特性使用0X2A37作為它的16位UUID孕蝉,因此它完整的128位UUID為:0x00002A37-0000-1000-8000-00805F9B34FB

BluetoothGattService

一個(gè)低功耗藍(lán)牙設(shè)備可以定義許多 Service, Service 可以理解為一個(gè)功能的集合。設(shè)備中每一個(gè)不同的 Service 都有一個(gè) 128 bit 的 UUID 作為這個(gè) Service 的獨(dú)立標(biāo)志腌逢。
這一個(gè)類通過 BluetoothGatt#getService 獲得降淮,如果當(dāng)前服務(wù)不可見那么將返回一個(gè) null。這一個(gè)類對(duì)應(yīng)上面說過的 Service搏讶。我們可以通過這個(gè)類的 getCharacteristic(UUID uuid) 進(jìn)一步獲取 Characteristic 實(shí)現(xiàn)藍(lán)牙數(shù)據(jù)的雙向傳輸佳鳖。

BluetoothGattCharacteristic

在 Service之下,又包括了許多的獨(dú)立數(shù)據(jù)項(xiàng)媒惕,我們把這些獨(dú)立的數(shù)據(jù)項(xiàng)稱作 Characteristic系吩。同樣的,每一個(gè) Characteristic 也有一個(gè)唯一的 UUID 作為標(biāo)識(shí)符吓笙。在 Android 開發(fā)中淑玫,建立藍(lán)牙連接后巾腕,我們說的通過藍(lán)牙發(fā)送數(shù)據(jù)給外圍設(shè)備就是往這些 Characteristic 中的 Value 字段寫入數(shù)據(jù)面睛;外圍設(shè)備發(fā)送數(shù)據(jù)給手機(jī)就是監(jiān)聽這些 Charateristic 中的 Value 字段有沒有變化,如果發(fā)生了變化尊搬,手機(jī)的 BLE API 就會(huì)收到一個(gè)監(jiān)聽的回調(diào)叁鉴。

這個(gè)類對(duì)應(yīng)上面提到的 Characteristic。通過這個(gè)類定義需要往外圍設(shè)備寫入的數(shù)據(jù)和讀取外圍設(shè)備發(fā)送過來的數(shù)據(jù)佛寿,這個(gè)類是中心設(shè)備和BLE設(shè)備之間數(shù)據(jù)通信的載體幌墓。

相當(dāng)于一個(gè)數(shù)據(jù)類型,它包括一個(gè)value和0~n個(gè)value的描述(BluetoothGattDescriptor)

BluetoothGattDescriptor

Characteristic之下,描述符冀泻,對(duì)Characteristic的描述常侣,包括范圍、計(jì)量單位等

Notification和Indication

Notification 外圍設(shè)備(硬件)設(shè)備給中心設(shè)備(手機(jī))發(fā)送一個(gè)數(shù)據(jù),無需接收方確認(rèn)弹渔。接收通知

Indication 外圍設(shè)備給中心設(shè)備(手機(jī))發(fā)送一個(gè)數(shù)據(jù),需要接收方確認(rèn)胳施。二者關(guān)系類似于TCP協(xié)議和UDP協(xié)議,效率上來講Notification比Indication要高肢专。在藍(lán)牙API中體現(xiàn)在notify() 方法和indicate()方法舞肆。

1.3與傳統(tǒng)藍(lán)牙ClassicBluetooth的比較

1.3.1藍(lán)牙模塊分類

藍(lán)牙模塊分類.png

1.3.2BLE和CLASSIC藍(lán)牙的比較

經(jīng)典藍(lán)牙模塊(BT):泛指支持藍(lán)牙協(xié)議在4.0以下的模塊,一般用于數(shù)據(jù)量比較大的傳輸博杖,如:語音椿胯、音樂、較高數(shù)據(jù)量傳輸?shù)忍旮=?jīng)典藍(lán)牙模塊可再細(xì)分為:傳統(tǒng)藍(lán)牙模塊和高速藍(lán)牙模塊哩盲。傳統(tǒng)藍(lán)牙模塊在2004年推出,主要代表是支持藍(lán)牙2.1協(xié)議的模塊,在智能手機(jī)爆發(fā)的時(shí)期得到廣泛支持廉油。高速藍(lán)牙模塊在2009年推出镣丑,速率提高到約24Mbps,是傳統(tǒng)藍(lán)牙模塊的八倍娱两,可以輕松用于錄像機(jī)至高清電視莺匠、PC至PMP、UMPC至打印機(jī)之間的資料傳輸十兢。

低功耗藍(lán)牙模塊(BLE):是指支持藍(lán)牙協(xié)議4.0或更高的模塊趣竣,也稱為BLE模塊(BluetoohLow EnergyModule),最大的特點(diǎn)是成本和功耗的降低旱物,應(yīng)用于實(shí)時(shí)性要求比較高遥缕,但是數(shù)據(jù)速率比較低的產(chǎn)品,如:遙控類的(鼠標(biāo)宵呛、鍵盤)单匣、傳感設(shè)備的數(shù)據(jù)發(fā)送(心跳帶、血壓計(jì)宝穗、溫度傳感器)等户秤。


接下來是第2個(gè)部分 ,實(shí)際工作中我們使用到的藍(lán)牙庫 BluetoothKit的使用:

二 . 框架介紹:

1.框架項(xiàng)目地址

https://github.com/dingjikerbo/BluetoothKit

2.框架優(yōu)點(diǎn)

一、統(tǒng)一解決Android藍(lán)牙通信過程中的兼容性問題

二逮矛、提供盡可能簡單易用的接口鸡号,屏蔽藍(lán)牙通信中的技術(shù)細(xì)節(jié),只開放連接须鼎,讀寫鲸伴,通知等語義。

三晋控、實(shí)現(xiàn)串行化任務(wù)隊(duì)列汞窗,統(tǒng)一處理藍(lán)牙通信中的失敗以及超時(shí),支持可配置的容錯(cuò)處理

四赡译、統(tǒng)一管理連接句柄仲吏,避免句柄泄露

五、方便監(jiān)控各設(shè)備連接狀態(tài)捶朵,在盡可能維持連接的情況下蜘矢,將最不活躍的設(shè)備自動(dòng)斷開。

六综看、便于多進(jìn)程APP架構(gòu)下藍(lán)牙連接的統(tǒng)一管理

七品腹、支持?jǐn)r截所有對(duì)藍(lán)牙原生接口的調(diào)用

3.基本使用

1.添加依賴compile 'com.inuker.bluetooth:library:1.4.0' 或直接導(dǎo)入依賴Liabrary模塊

2.在app模塊的Manifest中添加藍(lán)牙權(quán)限

 <!--藍(lán)牙相關(guān)權(quán)限-->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2. 掃描


BluetoothClient mClient = new BluetoothClient(context);

SearchRequest request = new SearchRequest.Builder()

        .searchBluetoothLeDevice(3000, 3)   // 先掃BLE設(shè)備3次,每次3s 

        .searchBluetoothClassicDevice(5000) // 再掃經(jīng)典藍(lán)牙5s,在實(shí)際工作中沒用到經(jīng)典藍(lán)牙的掃描

        .searchBluetoothLeDevice(2000)      // 再掃BLE設(shè)備2s

        .build();

mClient.search(request, new SearchResponse() {

    @Override

    public void onSearchStarted() {//開始搜素 

    }

    @Override

    public void onDeviceFounded(SearchResult device) {//找到設(shè)備 可通過manufacture過濾

        Beacon beacon = new Beacon(device.scanRecord);

        BluetoothLog.v(String.format("beacon for %s\n%s", device.getAddress(), beacon.toString()));

    }

    @Override

    public void onSearchStopped() {//搜索停止

    }

    @Override

    public void onSearchCanceled() {//搜索取消

    }

});

4.2連接

可以配置連接參數(shù)如下红碑,

BleConnectOptions options = new BleConnectOptions.Builder()

        .setConnectRetry(3)   // 連接如果失敗重試3次

        .setConnectTimeout(30000)   // 連接超時(shí)30s

        .setServiceDiscoverRetry(3)  // 發(fā)現(xiàn)服務(wù)如果失敗重試3次

        .setServiceDiscoverTimeout(20000)  // 發(fā)現(xiàn)服務(wù)超時(shí)20s

        .build();

mClient.connect(MAC, options, new BleConnectResponse() {

    @Override

    public void onResponse(int code, BleGattProfile data) {

    }

});

監(jiān)聽連接狀態(tài):

mClient.registerConnectStatusListener(MAC, mBleConnectStatusListener);

private final BleConnectStatusListener mBleConnectStatusListener = new BleConnectStatusListener() {

    @Override

    public void onConnectStatusChanged(String mac, int status) {

        if (status == STATUS_CONNECTED) {

        } else if (status == STATUS_DISCONNECTED) {

        }

    }

};

mClient.unregisterConnectStatusListener(MAC, mBleConnectStatusListener);

4.3 通訊


**讀Characteristic**

mClient.read(MAC, serviceUUID, characterUUID, new BleReadResponse() {

    @Override

    public void onResponse(int code, byte[] data) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**寫Characteristic**

要注意這里寫的byte[]不能超過20字節(jié)舞吭,如果超過了需要自己分成幾次寫泡垃。建議的辦法是第一個(gè)byte放剩余要寫的字節(jié)的長度。

mClient.write(MAC, serviceUUID, characterUUID, bytes, new BleWriteResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

這個(gè)寫是帶了WRITE_TYPE_NO_RESPONSE標(biāo)志的羡鸥,實(shí)踐中發(fā)現(xiàn)比普通的write快2~3倍蔑穴,建議用于固件升級(jí)。

mClient.writeNoRsp(MAC, serviceUUID, characterUUID, bytes, new BleWriteResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**讀Descriptor**

mClient.readDescriptor(MAC, serviceUUID, characterUUID, descriptorUUID, new BleReadResponse() {

    @Override

    public void onResponse(int code, byte[] data) {

    }

});

**寫Descriptor**

mClient.writeDescriptor(MAC, serviceUUID, characterUUID, descriptorUUID, bytes, new BleWriteResponse() {

    @Override

    public void onResponse(int code) {

    }

});

**打開Notify**

這里有兩個(gè)回調(diào)惧浴,onNotify是接收通知的存和。

mClient.notify(MAC, serviceUUID, characterUUID, new BleNotifyResponse() {

    @Override

    public void onNotify(UUID service, UUID character, byte[] value) {

    }

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**關(guān)閉Notify**

mClient.unnotify(MAC, serviceUUID, characterUUID, new BleUnnotifyResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**打開Indicate**

和Notify類似,

mClient.indicate(MAC, serviceUUID, characterUUID, new BleNotifyResponse() {

    @Override

    public void onNotify(UUID service, UUID character, byte[] value) {

    }

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**關(guān)閉Indicate**

mClient.unindicate(MAC, serviceUUID, characterUUID, new BleUnnotifyResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

**讀Rssi**

mClient.readRssi(MAC, new BleReadRssiResponse() {

    @Override

    public void onResponse(int code, Integer rssi) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

4.4 斷開

mClient.disconnect(MAC);

3.藍(lán)牙框架源碼解析

接下來 , 我以藍(lán)牙框架的"連接"功能為例來追蹤下源碼

@Override
    public void connect(String mac, BleConnectOptions options, BleConnectResponse response) {
        BluetoothLog.v(String.format("connect %s", mac));
        response = ProxyUtils.getUIProxy(response);
        mClient.connect(mac, options, response);
    }

1.BluetoothClientImpl 在這個(gè)實(shí)現(xiàn)里真正干了BluetoothClient的活

 @Override
    public void connect(String mac, BleConnectOptions options, final BleConnectResponse response) {
        Bundle args = new Bundle();
        args.putString(EXTRA_MAC, mac);
        args.putParcelable(EXTRA_OPTIONS, options);
        safeCallBluetoothApi(CODE_CONNECT, args, new BluetoothResponse() {
            @Override
            protected void onAsyncResponse(int code, Bundle data) {
                checkRuntime(true);
                if (response != null) {
                    data.setClassLoader(getClass().getClassLoader());
                    BleGattProfile profile = data.getParcelable(EXTRA_GATT_PROFILE);
                    response.onResponse(code, profile);
                }
            }
        });
    }

其中有一個(gè)關(guān)鍵方法 safeCallBluetoothApi

 private void safeCallBluetoothApi(int code, Bundle args, final BluetoothResponse response) {
        checkRuntime(true);

//        BluetoothLog.v(String.format("safeCallBluetoothApi code = %d", code));

        try {
            IBluetoothService service = getBluetoothService();

//            BluetoothLog.v(String.format("IBluetoothService = %s", service));

            if (service != null) {
                args = (args != null ? args : new Bundle());
                service.callBluetoothApi(code, args, response);
            } else {
                response.onResponse(SERVICE_UNREADY, null);
            }
        } catch (Throwable e) {
            BluetoothLog.e(e);
        }
    }

在這個(gè)方法里,首先拿到了藍(lán)牙的service(通過bindservice的方法),再調(diào)用了callBluetoothApi的方法
接下來我們來重點(diǎn)看下 BluetoothServiceImpl 中的callBluetoothApi方法 :

  @Override
    public void callBluetoothApi(int code, Bundle args, final IResponse response) throws RemoteException {
        Message msg = mHandler.obtainMessage(code, new BleGeneralResponse() {

            @Override
            public void onResponse(int code, Bundle data) {
                if (response != null) {
                    if (data == null) {
                        data = new Bundle();
                    }
                    try {
                        response.onResponse(code, data);
                    } catch (Throwable e) {
                        BluetoothLog.e(e);
                    }
                }
            }
        });

        args.setClassLoader(getClass().getClassLoader());
        msg.setData(args);
        msg.sendToTarget();
    }

這里面用了handler發(fā)送消息,在handleMessage方法中處理消息 :

@Override
    public boolean handleMessage(Message msg) {
        Bundle args = msg.getData();
        String mac = args.getString(EXTRA_MAC);
        UUID service = (UUID) args.getSerializable(EXTRA_SERVICE_UUID);
        UUID character = (UUID) args.getSerializable(EXTRA_CHARACTER_UUID);
        UUID descriptor = (UUID) args.getSerializable(EXTRA_DESCRIPTOR_UUID);
        byte[] value = args.getByteArray(EXTRA_BYTE_VALUE);
        BleGeneralResponse response = (BleGeneralResponse) msg.obj;

        switch (msg.what) {
            case CODE_CONNECT:
                BleConnectOptions options = args.getParcelable(EXTRA_OPTIONS);
                BleConnectManager.connect(mac, options, response);
                break;

            case CODE_DISCONNECT:
                BleConnectManager.disconnect(mac);
                break;

            case CODE_READ:
                BleConnectManager.read(mac, service, character, response);
                break;

            case CODE_WRITE:
                BleConnectManager.write(mac, service, character, value, response);
                break;

            case CODE_WRITE_NORSP:
                BleConnectManager.writeNoRsp(mac, service, character, value, response);
                break;

            case CODE_READ_DESCRIPTOR:
                BleConnectManager.readDescriptor(mac, service, character, descriptor, response);
                break;

            case CODE_WRITE_DESCRIPTOR:
                BleConnectManager.writeDescriptor(mac, service, character, descriptor, value, response);
                break;

            case CODE_NOTIFY:
                BleConnectManager.notify(mac, service, character, response);
                break;

            case CODE_UNNOTIFY:
                BleConnectManager.unnotify(mac, service, character, response);
                break;

            case CODE_READ_RSSI:
                BleConnectManager.readRssi(mac, response);
                break;

            case CODE_SEARCH:
                SearchRequest request = args.getParcelable(EXTRA_REQUEST);
                BluetoothSearchManager.search(request, response);
                break;

            case CODE_STOP_SESARCH:
                BluetoothSearchManager.stopSearch();
                break;

            case CODE_INDICATE:
                BleConnectManager.indicate(mac, service, character, response);
                break;

            case CODE_REQUEST_MTU:
                int mtu = args.getInt(EXTRA_MTU);
                BleConnectManager.requestMtu(mac, mtu, response);
                break;

            case CODE_CLEAR_REQUEST:
                int clearType = args.getInt(EXTRA_TYPE, 0);
                BleConnectManager.clearRequest(mac, clearType);
                break;

            case CODE_REFRESH_CACHE:
                BleConnectManager.refreshCache(mac);
                break;
        }
        return true;
    }

handleMessage方法中首先解析了bundle,然后區(qū)分不同的CODE處理不同的操作,針對(duì)"連接"的connect方法,接下來追蹤到BleConnectMaster.connect方法

@Override
    public void connect(BleConnectOptions options, BleGeneralResponse response) {
        getConnectDispatcher().connect(options, response);
    }

以上可以看出通過拿到dispatcher這個(gè)分發(fā)類來處理任務(wù),跳轉(zhuǎn)到dispatcher中的addNewRequest方法 ,

  private void addNewRequest(BleRequest request) {
        checkRuntime();

        if (mBleWorkList.size() < MAX_REQUEST_COUNT) { //最多的請(qǐng)求數(shù)是100
            request.setRuntimeChecker(this);
            request.setAddress(mAddress);
            request.setWorker(mWorker);//將worker設(shè)置為request,worker才是真正干活的
            mBleWorkList.add(request);
        } else {
            request.onResponse(Code.REQUEST_OVERFLOW);
        }

        scheduleNextRequest(10);
    }

scheduleNextRequest中通過handler發(fā)送了一個(gè)延時(shí)消息,消息處理的過程中調(diào)用了scheduleNextRequest()方法

   private void scheduleNextRequest(long delayInMillis) {
        mHandler.sendEmptyMessageDelayed(MSG_SCHEDULE_NEXT, delayInMillis);
    }
 @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_SCHEDULE_NEXT:
                scheduleNextRequest();
                break;
        }
        return true;
    }
 private void scheduleNextRequest() {
        if (mCurrentRequest != null) {
            return;
        }

        if (!ListUtils.isEmpty(mBleWorkList)) {
            mCurrentRequest = mBleWorkList.remove(0);
            //以下為重要代碼
            mCurrentRequest.process(this);
        }
    }

其中有一行關(guān)鍵的代碼 mCurrentRequest.process(this),接下來我們看下BleRequest 到底是怎么干活的?

  @Override
    final public void process(IBleConnectDispatcher dispatcher) {
        checkRuntime();

        mDispatcher = dispatcher;

        BluetoothLog.w(String.format("Process %s, status = %s", getClass().getSimpleName(), getStatusText()));
        //兼容性的的判斷
        if (!BluetoothUtils.isBleSupported()) {
            onRequestCompleted(Code.BLE_NOT_SUPPORTED);
        } else if (!BluetoothUtils.isBluetoothEnabled()) {
            onRequestCompleted(Code.BLUETOOTH_DISABLED);
        } else {
            try {
                registerGattResponseListener(this);
                processRequest();
            } catch (Throwable e) {
                BluetoothLog.e(e);
                onRequestCompleted(Code.REQUEST_EXCEPTION);
            }
        }
    }

這里面有一個(gè)關(guān)鍵的方法, processRequest(),這是一個(gè)抽象方法,子類需要實(shí)現(xiàn)的自己實(shí)現(xiàn),關(guān)于"連接"我們可以追蹤到 BleConnectRequest,以下的方法可以看到,最終判斷現(xiàn)在的連接狀態(tài)后 進(jìn)行連接的回調(diào)

 @Override
    public void processRequest() {
        processConnect();
    }

    private void processConnect() {
        mHandler.removeCallbacksAndMessages(null);
        mServiceDiscoverCount = 0;

        switch (getCurrentStatus()) {
            case Constants.STATUS_DEVICE_CONNECTED://連接成功
                processDiscoverService();//處理服務(wù) -- 讀服務(wù)
                break;

            case Constants.STATUS_DEVICE_DISCONNECTED://連接失敗,打開Gatt
                if (!doOpenNewGatt()) {
                    closeGatt();
                } else {
                    mHandler.sendEmptyMessageDelayed(MSG_CONNECT_TIMEOUT, mConnectOptions.getConnectTimeout());
                }
                break;

            case Constants.STATUS_DEVICE_SERVICE_READY:
                onConnectSuccess();
                break;
        }
    }

至此,分析告一段落,現(xiàn)在我們來分析下連接的另一個(gè)關(guān)鍵內(nèi)容 response 回調(diào)的處理,以連接為例,在BleConnectWorker中有一個(gè)連接回調(diào),根據(jù)不同的情況回調(diào)回去.

以上為初學(xué)藍(lán)牙和藍(lán)牙框架的一些感悟,以后有機(jī)會(huì)務(wù)必會(huì)完善此博客~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衷旅,一起剝皮案震驚了整個(gè)濱河市捐腿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柿顶,老刑警劉巖茄袖,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嘁锯,居然都是意外死亡宪祥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門家乘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝗羊,“玉大人,你說我怎么就攤上這事烤低≈饨唬” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵扑馁,是天一觀的道長。 經(jīng)常有香客問我凉驻,道長腻要,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任涝登,我火速辦了婚禮雄家,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胀滚。我一直安慰自己趟济,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布咽笼。 她就那樣靜靜地躺著顷编,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剑刑。 梳的紋絲不亂的頭發(fā)上媳纬,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天双肤,我揣著相機(jī)與錄音,去河邊找鬼钮惠。 笑死茅糜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的素挽。 我是一名探鬼主播蔑赘,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼预明!你這毒婦竟也來了米死?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤贮庞,失蹤者是張志新(化名)和其女友劉穎峦筒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窗慎,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡物喷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遮斥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峦失。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖术吗,靈堂內(nèi)的尸體忽然破棺而出尉辑,到底是詐尸還是另有隱情,我是刑警寧澤较屿,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布隧魄,位于F島的核電站,受9級(jí)特大地震影響隘蝎,放射性物質(zhì)發(fā)生泄漏购啄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一嘱么、第九天 我趴在偏房一處隱蔽的房頂上張望狮含。 院中可真熱鬧,春花似錦曼振、人聲如沸几迄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽映胁。三九已至,卻和暖如春集索,著一層夾襖步出監(jiān)牢的瞬間屿愚,已是汗流浹背汇跨。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妆距,地道東北人穷遂。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像娱据,于是被迫代替她去往敵國和親蚪黑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容