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

相关文章
|
2天前
|
JavaScript 前端开发 Java
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
IT寒冬使APP开发门槛提升,安卓程序员需转型。选项包括:深化Android开发,跟进Google新技术如Kotlin、Jetpack、Flutter及Compose;研究Android底层框架,掌握AOSP;转型Java后端开发,学习Spring Boot等框架;拓展大前端技能,掌握JavaScript、Node.js、Vue.js及特定框架如微信小程序、HarmonyOS;或转向C/C++底层开发,通过音视频项目如FFmpeg积累经验。每条路径都有相应的书籍和技术栈推荐,助你顺利过渡。
13 3
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
|
1天前
|
搜索推荐 Android开发 iOS开发
探索安卓与iOS开发的差异性与互补性
【8月更文挑战第19天】在移动应用开发的广阔天地中,安卓与iOS两大平台各据一方,引领着行业的潮流。本文将深入探讨这两个平台在开发过程中的不同之处以及它们之间的互补关系,旨在为开发者提供一个全面的视角,帮助他们更好地把握市场动态,优化开发策略。通过分析各自的开发环境、编程语言、用户界面设计、性能考量及市场分布等方面,我们将揭示安卓与iOS开发的独特魅力和挑战,同时指出如何在这两者之间找到平衡点,实现跨平台的成功。
|
1天前
|
移动开发 Android开发 iOS开发
揭秘移动开发之谜:安卓与iOS之间的技术鸿沟有多深?探索两大平台的开发差异及其对应用性能和用户体验的惊人影响!
【8月更文挑战第19天】在移动应用开发领域,安卓与iOS占据主导地位。两者在技术架构、开发工具及市场分布上各有特色。本文通过案例对比分析,展示安卓使用Java/Kotlin与iOS采用Swift/Objective-C的语言差异;探讨iOS统一细腻设计与安卓自定义Material Design的UI区别;并讨论安卓广泛市场覆盖与iOS高用户价值对开发者策略的影响。理解这些差异有助于制定有效的开发计划。
|
1天前
|
安全 Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的比较
【8月更文挑战第19天】 在移动应用开发的广阔天地中,安卓与iOS两大平台各领风骚。本文将深入探讨这两个平台在开发过程中的关键差异,从编程语言和工具到用户界面设计,再到市场分布和安全性考虑。我们将一窥究竟,是什么让安卓开发如此灵活多变,又是什么让iOS开发显得精致而统一。通过这篇比较分析,开发者可以更清晰地认识到各自平台的优势和挑战,从而做出更明智的开发决策。
6 0
|
Android开发 开发工具
Android官方网站
 http://wear.techbrood.com/sdk/installing/index.html?pkg=tools
1135 0
|
9天前
|
编解码 Android开发 iOS开发
探索安卓与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的世界中,安卓和iOS是两大主导力量。本文深入探讨了这两个平台在开发过程中的主要差异,并分析了这些差异如何影响项目的成功。通过对比分析,我们旨在为开发者提供决策时的参考,帮助他们根据项目需求和目标用户群体做出最合适的平台选择。
|
6天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的世界中,选择正确的平台是关键。本文通过比较安卓和iOS开发的核心差异,揭示平台选择如何影响应用的性能、用户体验和市场覆盖。我们将深入探讨各自的开发环境、编程语言、用户界面设计原则以及发布流程,以帮助开发者和企业做出明智的决策。
27 9
|
3天前
|
移动开发 开发工具 Android开发
探索安卓与iOS开发的差异:技术选择的影响
【8月更文挑战第17天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各领风骚。本文通过比较这两个平台的编程语言、开发工具及市场策略,揭示了技术选择对开发者和产品成功的重要性。我们将从开发者的视角出发,深入探讨不同平台的技术特性及其对项目实施的具体影响,旨在为即将步入移动开发领域的新手提供一个清晰的指南,同时给予资深开发者新的思考角度。
|
6天前
|
Java 开发工具 Android开发
探索安卓与iOS开发的差异:从新手到专家的旅程
在数字时代的浪潮中,移动应用开发成为了连接世界的桥梁。本文将带你走进安卓与iOS这两大移动操作系统的开发世界,通过比较它们的编程语言、开发工具和环境、用户界面设计以及市场分布等方面,揭示各自的独特之处。无论你是初涉编程的新手,还是寻求进阶的开发者,这篇文章都将为你提供宝贵的洞见,助你在移动应用开发的征途上一帆风顺。
20 5
|
4天前
|
vr&ar Android开发 iOS开发
探索安卓和iOS开发的未来趋势
在移动应用开发的广阔天地里,安卓和iOS两大平台如同双子星座般璀璨夺目。随着技术的不断进步,这两个平台的开发趋势也在悄然发生着变化。本文将带你一探究竟,看看未来安卓和iOS开发将会迎来哪些令人激动的新特性和挑战。让我们一起跟随技术的脚步,开启这场探索之旅吧!