Android 低功耗蓝牙开发(扫描、连接)

继续下一步。

三、扫描低功耗蓝牙


扫描低功耗蓝牙,首先要有触发的地方,其次要有显示结果的地方,这些都需要进行UI的处理,那么下面进行布局的修改和增加,修改activity_main.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“.MainActivity”>

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv_device”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_above=“@+id/btn_start_scan”

android:overScrollMode=“never” />

<com.google.android.material.button.MaterialButton

android:id=“@+id/btn_start_scan”

android:layout_width=“match_parent”

android:layout_height=“50dp”

android:layout_above=“@+id/btn_stop_scan”

android:layout_margin=“6dp”

android:insetTop=“0dp”

android:insetBottom=“0dp”

android:text=“开始扫描” />

<com.google.android.material.button.MaterialButton

android:id=“@+id/btn_stop_scan”

android:layout_width=“match_parent”

android:layout_height=“50dp”

android:layout_alignParentBottom=“true”

android:layout_margin=“6dp”

android:insetTop=“0dp”

android:insetBottom=“0dp”

android:text=“停止扫描” />

下面进行列表item的布局编写,在layout下新建一个item_device_rv.xml文件,文件代码如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:foreground=“?attr/selectableItemBackground”

android:orientation=“vertical”>

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:gravity=“center_vertical”

android:padding=“16dp”>

<ImageView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:src=“@drawable/ic_bluetooth_blue” />

<LinearLayout

android:layout_width=“0dp”

android:layout_height=“wrap_content”

android:layout_weight=“1”

android:orientation=“vertical”

android:paddingStart=“12dp”>

<TextView

android:id=“@+id/tv_device_name”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:ellipsize=“end”

android:singleLine=“true”

android:text=“设备名称”

android:textColor=“@color/black”

android:textSize=“16sp” />

<TextView

android:id=“@+id/tv_mac_address”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_marginTop=“8dp”

android:ellipsize=“end”

android:singleLine=“true”

android:text=“Mac地址” />

<TextView

android:id=“@+id/tv_rssi”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“信号强度” />

<View

android:layout_width=“match_parent”

android:layout_height=“0.5dp”

android:background=“#EEE” />

这里面有一个图标,使用路径绘制的ic_bluetooth_blue.xml,放在drawable文件夹下,代码如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<vector xmlns:android=“http://schemas.android.com/apk/res/android”

android:width=“36dp”

android:height=“36dp”

android:autoMirrored=“true”

android:tint=“#42A5F5”

android:viewportWidth=“24.0”

android:viewportHeight=“24.0”>

<path

android:fillColor=“@android:color/white”

android:pathData=“M14.58,12.36l1.38,1.38c0.28,0.28 0.75,0.14 0.84,-0.24c0.12,-0.48 0.18,-0.99 0.18,-1.5c0,-0.51 -0.06,-1.01 -0.18,-1.48c-0.09,-0.38 -0.56,-0.52 -0.84,-0.24l-1.39,1.38C14.39,11.85 14.39,12.17 14.58,12.36zM18.72,7.51l-0.05,0.05c-0.25,0.25 -0.3,0.62 -0.16,0.94c0.47,1.07 0.73,2.25 0.73,3.49c0,1.24 -0.26,2.42 -0.73,3.49c-0.14,0.32 -0.09,0.69 0.16,0.94l0,0c0.41,0.41 1.1,0.29 1.35,-0.23c0.63,-1.3 0.98,-2.76 0.98,-4.3c-0.01,-1.48 -0.34,-2.89 -0.93,-4.16C19.83,7.22 19.13,7.1 18.72,7.51zM15,7l-4.79,-4.79C10.07,2.07 9.89,2 9.71,2h0C9.32,2 9,2.32 9,2.71v6.88L5.12,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L8.59,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.88C9,21.68 9.32,22 9.71,22h0c0.19,0 0.37,-0.07 0.5,-0.21L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12L15,8.42C15.39,8.03 15.39,7.39 15,7zM11,5.83l1.88,1.88L11,9.59V5.83zM12.88,16.29L11,18.17v-3.76L12.88,16.29z” />

好了,现在针对于这个布局方面的内容告一段落,下面先运行一下了:在这里插入图片描述

进行下一步操作。

先进行页面的初始化。新增一个initView的方法。

private static final String TAG = MainActivity.class.getSimpleName();

/**

  • nordic扫描回调

*/

private ScanCallback scanCallback;

/**

  • 初始化

*/

private void initView() {

RecyclerView rvDevice = findViewById(R.id.rv_device);

findViewById(R.id.btn_start_scan).setOnClickListener(v -> startScanDevice());

findViewById(R.id.btn_stop_scan).setOnClickListener(v -> stopScanDevice());

//扫描结果回调

scanCallback = new ScanCallback() {

@Override

public void onScanResult(int callbackType, @NonNull ScanResult result) {

Log.d(TAG, “name:” + result.getDevice().getName() + “,rssi:” + result.getRssi());

}

@Override

public void onScanFailed(int errorCode) {

throw new RuntimeException(“Scan error”);

}

};

}

这个initView主要是页面的初始化,列表在后面进行配置,根据扫描结果来定,然后就是配置扫描回调,这里注意导包的问题,不要到错了包。

在这里插入图片描述

然后还有一个开始扫描和停止扫描的方法。

/**

  • 开始扫描设备

*/

public void startScanDevice() {

BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();

scanner.startScan(scanCallback);

}

/**

  • 停止扫描设备

*/

public void stopScanDevice() {

BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();

scanner.stopScan(scanCallback);

}

下面在onCreate方法中调用initView()方法。

在这里插入图片描述

下面就可以开始运行了。运行之后点击开始扫描按钮,就会扫描附近的低功耗蓝牙设备,(请在附近有已打开低功耗蓝牙时进行扫描)可以在日志栏处进行打印。

在这里插入图片描述

这里很明显,扫描到了一些蓝牙设备,并且很多设备没有设备名称。既然有了结果,那么下面就是将扫描到的结果显示在列表上,这样才更直观。

四、显示扫描设备


下面将扫描结果渲染到列表上,首先明确列表要显示扫描设备的那些信息,从item来看有设备名、Mac地址、信号强度。那么可以根据这一个扫描的信息构建一个设备类,新建一个BleDevice类,代码如下:

package com.llw.bledemo.bean;

import android.bluetooth.BluetoothDevice;

/**

  • @author llw

  • @description BleDevice

  • @date 2021/7/21 19:20

*/

public class BleDevice {

private BluetoothDevice device;

private int rssi;

private String realName;//真实名称

/**

  • 构造Device

  • @param device 蓝牙设备

  • @param rssi 信号强度

  • @param realName 真实名称

*/

public BleDevice(BluetoothDevice device, int rssi, String realName) {

this.device = device;

this.rssi = rssi;

this.realName = realName;

}

public BluetoothDevice getDevice(){

return device;

}

public int getRssi(){

return rssi;

}

public void setRssi(int rssi) {

this.rssi = rssi;

}

public String getRealName(){

return realName;

}

public void setRealName(String realName) {

this.realName = realName;

}

@Override

public boolean equals(Object object) {

if(object instanceof BleDevice){

final BleDevice that =(BleDevice) object;

return device.getAddress().equals(that.device.getAddress());

}

return super.equals(object);

}

}

下面来写这个适配器,新建一个BleDeviceAdapter类,代码如下:

package com.llw.bledemo.adapter;

import com.chad.library.adapter.base.BaseQuickAdapter;

import com.chad.library.adapter.base.viewholder.BaseViewHolder;

import com.llw.bledemo.R;

import com.llw.bledemo.bean.BleDevice;

import java.util.List;

/**

  • @author llw

  • @description BleDeviceAdapter

  • @date 2021/7/21 19:34

*/

public class BleDeviceAdapter extends BaseQuickAdapter<BleDevice, BaseViewHolder> {

public BleDeviceAdapter(int layoutResId, List data) {

super(layoutResId, data);

}

@Override

protected void convert(BaseViewHolder holder, BleDevice bleDevice) {

holder.setText(R.id.tv_device_name, bleDevice.getRealName())

.setText(R.id.tv_mac_address, bleDevice.getDevice().getAddress())

.setText(R.id.tv_rssi, bleDevice.getRssi() + " dBm");

}

}

下面回到MainActivity中对列表进行适配,先定义变量

/**

  • 设备列表

*/

private List mList = new ArrayList<>();

/**

  • 列表适配器

*/

private BleDeviceAdapter deviceAdapter;

然后在initView方法中进行列表配置,代码如下:

//列表配置

deviceAdapter = new BleDeviceAdapter(R.layout.item_device_rv, mList);

rvDevice.setLayoutManager(new LinearLayoutManager(this));

//启用动画

deviceAdapter.setAnimationEnable(true);

//设置动画方式

deviceAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.SlideInRight);

rvDevice.setAdapter(deviceAdapter);

添加位置如下:

在这里插入图片描述

下面就是将扫描结果添加到列表中了,可以写一个方法addDeviceList(),代码如下:

/**

  • 添加到设备列表

  • @param bleDevice 蓝牙设备

*/

private void addDeviceList(BleDevice bleDevice) {

if (!mList.contains(bleDevice)) {

bleDevice.setRealName(bleDevice.getRealName() == null ? “UNKNOWN” : bleDevice.getRealName());

mList.add(bleDevice);

} else {

//更新设备信号强度值

for (BleDevice device : mList) {

device.setRssi(bleDevice.getRssi());

}

}

//刷新列表适配器

deviceAdapter.notifyDataSetChanged();

}

然后在扫描的回调中进行调用即可。

在这里插入图片描述

点击开始的时候清理一下列表。

在这里插入图片描述

下面运行一下:

在这里插入图片描述

增加一个表示搜索的效果,在activity_main.xml中增加

<androidx.core.widget.ContentLoadingProgressBar

android:id=“@+id/loading_progress_bar”

style=“?android:attr/progressBarStyleHorizontal”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:indeterminate=“true”

android:indeterminateTint=“@color/purple_200”

android:visibility=“invisible”

tools:ignore=“UnusedAttribute”/>

然后这个进度条设置在列表的上面。

在这里插入图片描述

回到MainActivity,创建变量:

/**

  • 加载进度条

*/

private ContentLoadingProgressBar loadingProgressBar;

绑定视图

在这里插入图片描述

控制视图

在这里插入图片描述

运行一下:

在这里插入图片描述

五、连接设备


连接Ble设备其实也很简单,难的是连接之外的东西,先来构想一下连接功能的业务逻辑,点击设备列表中的设备,进行连接,先显示一个加载布局,表示现在正在连接,然后停止扫描,在根据设备的mac地址去连接这个设备,然后在连接设备的回调中处理连接设备的结果。嗯,就是这样。下面来编码,首先是加载布局的问题。在activity_main.xml中增加如下布局代码:

<LinearLayout

android:id=“@+id/lay_connecting_loading”

android:layout_centerInParent=“true”

android:layout_width=“160dp”

android:layout_height=“160dp”

android:orientation=“vertical”

android:visibility=“invisible”

android:background=“@color/white”

android:gravity=“center”>

<ProgressBar

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:indeterminate=“true”

android:indeterminateTint=“@color/purple_200” />

<TextView

android:layout_marginTop=“12dp”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“连接中…”

android:textColor=“@color/black”

android:textSize=“@dimen/sp_14” />

添加位置如下图

在这里插入图片描述

然后在MainActivity中创建变量

/**

  • 等待连接

*/

private LinearLayout layConnectingLoading;

绑定视图

在这里插入图片描述

下面新增一个方法,用来连接设备。在点击设备列表Item的时候调用。

/**

  • 连接设备

  • @param bleDevice 蓝牙设备

*/

private void connectDevice(BleDevice bleDevice) {

//显示连接等待布局

layConnectingLoading.setVisibility(View.VISIBLE);

//停止扫描

stopScanDevice();

//获取远程设备

BluetoothDevice device = bleDevice.getDevice();

//连接gatt

device.connectGatt(this, false, new BluetoothGattCallback() {

@Override

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

switch (newState) {

case BluetoothProfile.STATE_CONNECTED://连接成功

Log.d(TAG,“连接成功”);

runOnUiThread(() -> {

layConnectingLoading.setVisibility(View.GONE);

showMsg(“连接成功”);

});

break;

case BluetoothProfile.STATE_DISCONNECTED://断开连接

Log.d(TAG,“断开连接”);

runOnUiThread(() -> {

layConnectingLoading.setVisibility(View.GONE);

showMsg(“断开连接”);

});

break;

default:

break;

}

}

});

}

在initView()中设置列表点击。

//item点击事件

deviceAdapter.setOnItemClickListener((adapter, view, position) -> {

//连接设备

connectDevice(mList.get(position));

});

在这里插入图片描述

OK,下面运行一下:

在这里插入图片描述

这个布局背景是白色的不是很明显,改一下好了。在drawable文件夹下新建一个shape_loading_bg.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<stroke

android:width=“1dp”

android:color=“@color/purple_500” />

然后设置到这个布局中

在这里插入图片描述

运行看看

在这里插入图片描述

嗯,还可以,就这样了。

有连接设备就自然有断开连接设备。再增加两个变量

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
ding=“utf-8”?>

<stroke

android:width=“1dp”

android:color=“@color/purple_500” />

然后设置到这个布局中

在这里插入图片描述

运行看看

在这里插入图片描述

嗯,还可以,就这样了。

有连接设备就自然有断开连接设备。再增加两个变量

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-Nexx2iUF-1714558880056)]

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android(Low Energy Bluetooth)抓包是指通过对Android设备与使用技术的其他设备之间的通信数据进行捕获和分析,以了解通信过程和内容。 在Android中进行抓包需要以下步骤: 1. 配置设备:首先,确保Android设备支持,并且已经启用了能。如果设备不支持,则无法进行抓包。 2. 安装抓包工具:在Android设备上安装支持抓包的工具,例如nRF Sniffer。这些工具可以在Google Play商店或开发者官网上获得。 3. 配置抓包工具:根据抓包工具的说明,对其进行配置和设置。通常,需要选择要捕获的设备以及捕获的报文类型,例如广播、扫描响应等。 4. 开始抓包:在设备配置好后,可以开始进行抓包。打开抓包工具,并按照其说明开始捕获通信数据。 5. 分析数据:抓包工具会将捕获的通信数据保存在文件中。将这些文件导入到数据分析工具中,以查看发送和接收的数据包,分析数据包的内容和结构,以及了解通信过程中可能存在的问题。 总结来说,Android抓包是一种通过安装并配置抓包工具,来捕获和分析设备之间通信数据的过程。这可以帮助开发人员和研究人员了解的工作原理、调试和分析通信问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值