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

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

一、前言

在上一篇文章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) {
 
    }

4. 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到一步一步地去理解具体的调用,最后已经算是走通了整个蓝牙开发流程,如果想再深入点的话就要考虑具体的底层实现,和真实项目中怎么去更好地封装!

相关文章
|
3天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
8天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
10天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
10天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
12天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
11天前
|
存储 XML JSON
探索安卓开发:从新手到专家的旅程
【10月更文挑战第36天】在这篇文章中,我们将一起踏上一段激动人心的旅程,从零基础开始,逐步深入安卓开发的奥秘。无论你是编程新手,还是希望扩展技能的老手,这里都有适合你的知识宝藏等待发掘。通过实际的代码示例和深入浅出的解释,我们将解锁安卓开发的关键技能,让你能够构建自己的应用程序,甚至贡献于开源社区。准备好了吗?让我们开始吧!
23 2
|
12天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
20天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
下一篇
无影云桌面