设置设备可见对于服务端是必须的,客户端设不设置无所谓。
如果服务端不可见,配对过的设备也搜索到并可以连接上,但是不能通信,没有配对过的设备连搜索都搜索不到。
可见时间的取值范围是0到120,单位是秒,0表示永久可见。
手机上的蓝牙可见仅限一次连接有效。也就是说,一次连接断开以后,下次再等待客户端连接的时候,还需要再设置一次设备可见。
/**
* 设置设备可见
* 0 ~ 120
*/
public void setDuration() {
Intent duration = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
duration.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
mActivity.startActivity(duration);
}
扫描附近的蓝牙设备
扫描附近设备的设备,需要注册一个广播接收者,来接收扫描到的结果。
需要注意的是,接收扫描结果的广播接收者必须使用动态注册,不能在清单文件里注册!
注册搜索蓝牙设备的广播接收者
// 获取设备的广播接收者
FoundDeviceBroadcastReceiver mFoundDeviceBroadcastReceiver = new FoundDeviceBroadcastReceiver();
// 注册receiver监听
IntentFilter mFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
/**
* 注册搜索蓝牙设备的广播接收者
*/
public void registerFoundDeviceReceiver() {
mActivity.registerReceiver(mFoundDeviceBroadcastReceiver, mFilter);
}
反注册搜索蓝牙设备的广播接收者
// 获取设备的广播接收者
FoundDeviceBroadcastReceiver mFoundDeviceBroadcastReceiver = new FoundDeviceBroadcastReceiver();
/**
* 反注册搜索蓝牙设备的广播接收者
*/
public void unregisterReceiver() {
mActivity.unregisterReceiver(mFoundDeviceBroadcastReceiver);
}
广播接收者
/**
* Created by kqw on 2016/8/2.
* 蓝牙的广播接收者
*/
public class FoundDeviceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "FoundDeviceBroadcast";
private static OnFoundDeviceListener mOnFoundDeviceListener;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 获取设备
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 扫描发现的设备
if (null != mOnFoundDeviceListener) {
mOnFoundDeviceListener.foundDevice(btDevice);
}
}
……
}
public void setOnFoundDeviceListener(OnFoundDeviceListener listener) {
mOnFoundDeviceListener = listener;
}
}
开始扫描附近的蓝牙设备
/**
* 开始扫描设备
*/
public void startDiscovery() {
Log.i(TAG, "startDiscovery: ");
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
} else {
// TODO 这里可以先获取已经配对的设备
// Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// 开始扫描设备
mBluetoothAdapter.startDiscovery();
}
}
获取已经配对的设备
扫描附近的蓝牙设备是一个很消耗性能的操作,在扫描之前,可以先获取已经配对过的设备,如果已经配对过,就不用再扫描了。
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
蓝牙连接
获取到附近的设备以后,就可以通过MAC地址进行配对连接了。
配对
没有配对过的设备,在连接之前是需要配对的,配对成功才可以连接、通信。
配对可以手动点击,根据配对码进行配对,也可以设置自动配对。手动配对没什么好说的,这里介绍自动配对
还是用到上面的蓝牙广播接收者,我们在清单文件里添加Action
<!-- 蓝牙广播接收者 -->
<receiver android:name=".receiver.FoundDeviceBroadcastReceiver">
<intent-filter>
<!-- 添加配对请求 -->
<action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
</intent-filter>
</receiver>
注意:这里的自动配对仅支持4.4.2以上系统,以下的版本想要实现需要用到反射
/**
* Created by kqw on 2016/8/2.
* 蓝牙的广播接收者
*/
public class FoundDeviceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "FoundDeviceBroadcast";
private static OnFoundDeviceListener mOnFoundDeviceListener;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 获取设备
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
if (new ConfigUtil(context).getPairingConfirmation()) {
// 收到配对请求
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 同意请求
btDevice.setPairingConfirmation(true);
} else {
Log.i(TAG, "onReceive: 4.4.2 以下版本的设备需要通过反射实现自动配对");
}
}
}
……
}
}
连接
服务端等待连接
服务端开启连接,需要开启一个阻塞线程,等待客户端的连接,类似这样
try {
// 等待客户端连接 阻塞线程 连接成功继续向下执行 连接失败抛异常
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
break;
}
客户端发起连接
客户端发起连接,如果没有配对过,需要先进行配对,连接同样是一个阻塞线程,连接成功会继续向下执行,连接失败会抛异常,类似这样
try {
……
// 开始连接 阻塞线程 连接成功继续执行 连接失败抛异常
mmSocket.connect();
} catch (IOException e) {
// 连接失败
e.printStackTrace();
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2);
}
……
}
通信
–
接收数据
连接成功以后,需要开启一个线程,一直循环读取数据流,类似这样
// 只有蓝牙处于连接状态就一直循环读取数据
while (mState == STATE_CONNECTED) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// 读取到数据的回调
……
} catch (IOException e) {
// 读取数据出现异常
Log.e(TAG, "disconnected", e);
……
}
}
发送数据
/**
* 发数据
### 最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套**腾讯、头条、阿里、美团等公司20年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 **高级架构技术进阶脑图、Android开发面试专题资料**,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**
![](https://img-blog.csdnimg.cn/img_convert/f066054fe2d4886e067d3c92b4f42d5e.webp?x-oss-process=image/format,png)
**【算法合集】**
![](https://img-blog.csdnimg.cn/img_convert/c082fbe2dc412727be19c009ceaeabc4.webp?x-oss-process=image/format,png)
**【延伸Android必备知识点】**
![](https://img-blog.csdnimg.cn/img_convert/37add97ab1fd23bac9e1e1aeeac9a3fd.webp?x-oss-process=image/format,png)
,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套**腾讯、头条、阿里、美团等公司20年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 **高级架构技术进阶脑图、Android开发面试专题资料**,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**
[外链图片转存中...(img-C922t2uT-1718868714066)]
**【算法合集】**
[外链图片转存中...(img-o0UyYSaS-1718868714067)]
**【延伸Android必备知识点】**
[外链图片转存中...(img-9ACXolPJ-1718868714067)]