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

相关文章
|
14天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
14天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
41 14
|
14天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
15天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
27天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
29天前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
24 1
|
1月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
27天前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!