美文网首页Android开发Android开发Android技术知识
Android 蓝牙BLE开发从官方源码demo开始(二)

Android 蓝牙BLE开发从官方源码demo开始(二)

作者: 程序猿在广东 | 来源:发表于2018-12-26 11:13 被阅读5次

    一、前言

    在上一篇文章Android 蓝牙BLE开发从官方源码demo开始(一)我们已经看了官方的demo,知道了怎么开始配置Android蓝牙4.0,并且也成功地进行扫描并获取回调的蓝牙设备参数,然后对参数进行处理展示,其中第一个参数device,表示一个远程蓝牙设备,里面有它独有的蓝牙地址Address和Name;我们要拿到这个设备Address进行蓝牙连接和读写操作。

    谷歌给我们提供了官方源码demo:
    https://github.com/googlesamples/android-BluetoothLeGatt
    接下来我们继续来学习谷歌官方给我们提供的蓝牙BLE源码

    二、创建BluetoothLeService服务类并初始化蓝牙连接

    在官方demo中,蓝牙ble的连接和读写操作都是在DeviceControlActivity中实现,可以下载demo源码,编译运行一遍!
    来到此Activity,我们先看onCreate()方法可知,程序先执行bindService开启了一个服务

     Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
     bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
    

    并在服务回调已经成功连接时,获取了BlueToohtLeService的实例,接着就执行蓝牙连接操作:

        // Code to manage Service lifecycle.
        private final ServiceConnection mServiceConnection = new ServiceConnection() {
     
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder service) {
                mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
                if (!mBluetoothLeService.initialize()) {
                    Log.e(TAG, "Unable to initialize Bluetooth");
                    finish();
                }
                // Automatically connects to the device upon successful start-up initialization.
                mBluetoothLeService.connect(mDeviceAddress);
            }
     
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                mBluetoothLeService = null;
            }
        };
    

    这个BlueToohtLeService类既然是服务类,那它父类肯定是继承于Service;接着实现了Service的先进入onBind()方法;
    1.onBind()是使用bindService开启的服务才会有回调的一个方法。
    这里官方demo在onBind()方法给我们的Activity返回了BluetoothLeService实例,方便Activity后续的连接和读写操作;

        private final IBinder mBinder = new LocalBinder();
     
        public class LocalBinder extends Binder {
            BluetoothLeService getService() {
                return BluetoothLeService.this;
            }
        }
     
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    

    2.当服务调用unbindService时,服务的生命周期将会进入onUnbind()方法;接着执行了关闭蓝牙的方法;

        @Override
        public boolean onUnbind(Intent intent) {
            // After using a given device, you should make sure that BluetoothGatt.close() is called
            // such that resources are cleaned up properly.  In this particular example, close() is
            // invoked when the UI is disconnected from the Service.
            close();
            return super.onUnbind(intent);
        }
    

    3.initialize() 初始化蓝牙适配器;接着在这demo里这个方法是在服务建立后在Activity通过拿到BlueToohtLeService实例调用的。

        /**
         * Initializes a reference to the local Bluetooth adapter.
         *
         * @return Return true if the initialization is successful.
         */
        public boolean initialize() {
            // For API level 18 and above, get a reference to BluetoothAdapter through
            // BluetoothManager.
            if (mBluetoothManager == null) {
                mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
                if (mBluetoothManager == null) {
                    Log.e(TAG, "Unable to initialize BluetoothManager.");
                    return false;
                }
            }
     
            mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (mBluetoothAdapter == null) {
                Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
                return false;
            }
     
            return true;
        }
    

    4.connect()方法 传入蓝牙地址进行连接蓝牙操作;先判断蓝牙适配器是否为空,然后判断是否刚断开需要重连的设备,否则就通过蓝牙适配器获取BluetoothGatt实例去连接蓝牙操作,后续还会使用到BluetoothGatt去读写操作和断开、关闭操作;

        public boolean connect(final String address) {
            if (mBluetoothAdapter == null || address == null) {
                Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
                return false;
            }
     
            // Previously connected device.  Try to reconnect.
            // 以前连接的设备。 尝试重新连接。
            if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                    && mBluetoothGatt != null) {
                Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
                if (mBluetoothGatt.connect()) {
                    mConnectionState = STATE_CONNECTING;
                    return true;
                } else {
                    return false;
                }
            }
     
            final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
            if (device == null) {
                Log.w(TAG, "Device not found.  Unable to connect.");
                return false;
            }
            // We want to directly connect to the device, so we are setting the autoConnect 我们想直接连接到设备,因此我们设置autoConnect
            // parameter to false.
            mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
            Log.d(TAG, "Trying to create a new connection.");
            mBluetoothDeviceAddress = address;
            mConnectionState = STATE_CONNECTING;
            return true;
        }
    

    5.BluetoothGattCallback 回调;这个回调可以说很重要,核心部分,主要对BluetoothGatt的蓝牙连接、断开、读、写、特征值变化等的回调监听,然后我们可以将这些回调信息通过广播机制传播回给广播监听器。

        private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
     
            }
     
            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
     
            }
     
            @Override
            public void onCharacteristicRead(BluetoothGatt gatt,
                                             BluetoothGattCharacteristic characteristic,
                                             int status) {
            }
     
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt,
                                                BluetoothGattCharacteristic characteristic) {
     
            }
        };
    

    三、广播监听器

    在这个官方demo中,就是使用了广播来作为activity和service之间的数据传递;继续回到源码:activity开启前面所说的服务之后,就注册了这个mGattUpdateReceiver广播;

        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
            if (mBluetoothLeService != null) {
                final boolean result = mBluetoothLeService.connect(mDeviceAddress);
                Log.d(TAG, "Connect request result=" + result) ;
            }
    
       private static IntentFilter makeGattUpdateIntentFilter() {
            final IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
            intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
            intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
            intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
            return intentFilter;
        }
    

    关于这个广播的回调监听如下:有注释就不多解释了,它的作用就是接收从service发送回来的信息;上文有说到BluetoothGattCallback,就是从这里发送广播的。

       // Handles various events fired by the Service. 处理服务部门发起的各种事件
        // ACTION_GATT_CONNECTED: connected to a GATT server. 连接到GATT服务器。
        // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. 与GATT服务器断开连接。
        // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.发现GATT服务
        // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read
        //                        or notification operations. 从设备接收数据。 这可能是阅读的结果
        //     //或通知操作。
        private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                    mConnected = true;
                    updateConnectionState(R.string.connected);
                    invalidateOptionsMenu();
                } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                    mConnected = false;
                    updateConnectionState(R.string.disconnected);
                    invalidateOptionsMenu();
                    clearUI();
                } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                    // Show all the supported services and characteristics on the user interface.
                    displayGattServices(mBluetoothLeService.getSupportedGattServices());
                } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                    displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
                }
            }
        };
    

    这里留意一下:当连接成功后,首先service那边会发现服务特征值,通过广播传输回来,然后执行下面的方法:

       displayGattServices(mBluetoothLeService.getSupportedGattServices());
    

    四、其他方法

    1. setCharacteristicNotification();调用此方法开启特征值的通知;
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    

    2.开启读,我们可以用如下方法,但是此方法有个缺点:要不断轮询 才能达到不断监听;

    mBluetoothGatt.readCharacteristic(characteristic);
    

    如果成功,将返回BluetoothGattCallback回调 进入其如下方法

            @Override
            public void onCharacteristicRead(BluetoothGatt gatt,
                                             BluetoothGattCharacteristic characteristic,
                                             int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                }
            }
    

    使用如下方法,传入特征值,true

    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    如果成功,将返回BluetoothGattCallback回调 进入其如下方法

            @Override
            public void onCharacteristicRead(BluetoothGatt gatt,
                                             BluetoothGattCharacteristic characteristic,
                                             int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                }
            }
    

    具体选择哪种方法就要看具体需求了。

    3.还有一个很重要的方法,demo没有给出例子的:
    mBluetoothGatt.writeCharacteristic(characteristic);
    这是向蓝牙设备写入数据,几乎都会用到的。
    如果成功,将返回BluetoothGattCallback回调 进入其如下方法

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                                          BluetoothGattCharacteristic characteristic,
                                          int status) {
     
        }
    
    1. disconnect();调用BluetoothGatt.disconnect()断开蓝牙连接;
        public void disconnect() {
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.w(TAG, "BluetoothAdapter not initialized");
                return;
            }
            mBluetoothGatt.disconnect();
        }
    

    5.close();关闭蓝牙

        /**
         * After using a given BLE device, the app must call this method to ensure resources are
         * released properly.
         */
        public void close() {
            if (mBluetoothGatt == null) {
                return;
            }
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }
    

    最后,关于Android蓝牙BLE的使用在此结束,我从下载官方demo到一步一步地去理解具体的调用,最后已经算是走通了整个蓝牙开发流程,如果想再深入点的话就要考虑具体的底层实现,和真实项目中怎么去更好地封装!

    扫一扫关注我的微信公众号:程序猿在广东

    my二维码.jpg

    相关文章

      网友评论

        本文标题:Android 蓝牙BLE开发从官方源码demo开始(二)

        本文链接:https://www.haomeiwen.com/subject/rzzclqtx.html