Android通过BluetoothAdapter来检测蓝牙状态,打开或关闭蓝牙,扫描蓝牙并得到蓝牙信息等功能。
在使用时,通过BluetoothAdapter.getDefaultAdapter()方法来获取系统的BluetoothAdapter,如果系统支持蓝牙则会返回实例,如果不支持,则返回空;写个简单的demo来看看吧:
先在MainActivity.class
中定义BluetoothAdapter、BluetoothDevice等变量
public class MainActivity extends Activity implements View.OnClickListener,TBluetoothListAdapter.OnBluetoothItemClickListener {
//adapter
private BluetoothAdapter bluetoothAdapter ;
//远程的蓝牙设备,可以创建到各个蓝牙设备的连接,并获取远程蓝牙设备的信息(如名字,地址,类名和匹配状态)
private BluetoothDevice mDevice ;
//用列表显示搜索得到的蓝牙设备信息
private RecyclerView rvBluetooth ;
//自定义的数据展示adapter
private TBluetoothListAdapter adapter ;
//简单的蓝牙信息实体类,用于展示
private List<TBlueToothInfo> datas = new ArrayList<>() ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main) ;
initView();
initData();
}
}
然后在initView方法中初始化布局等相关信息:
private void initView() {
//初始化布局
rvBluetooth = (RecyclerView)findViewById(R.id.rv_bluetooth) ;
findViewById(R.id.tv_search_bluetooth).setOnClickListener(this) ;
//初始化TBluetoothListAdapter
adapter = new TBluetoothListAdapter(datas,this) ;
//设置数据列表的点击事件
adapter.setOnBluetoothItemClickListener(this) ;
rvBluetooth.setAdapter(adapter) ;
rvBluetooth.setLayoutManager(new LinearLayoutManager(this)) ;
}
在initData方法中初始化bluetoothAdapter
private void initData() {
//初始化adapter和权限
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
通过点击事件,开始判断蓝牙状态,如果未打开则打开蓝牙,如果可用,则开始扫描蓝牙设备:
@Override
public void onClick(View v) {
if(bluetoothAdapter != null) {//代表系统有蓝牙功能
if(!bluetoothAdapter.isEnabled()) { //如果蓝牙不可用
//启动蓝牙
Intent bluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) ;
startActivity(bluetoothIntent);
//搜索蓝牙
searchBluetooth();
} else { // 蓝牙可用
//搜索蓝牙
searchBluetooth();
}
}
}
搜索蓝牙的方法如下,主要是通过发送系统广播来监听扫描得到的结果。BluetoothDevice有多个ACTION,这里我们用到了2个
- ACTION_FOUND:扫描到任一远程蓝牙设备时,会发送;
- ACTION_DISCOVERY_FINISHED:扫描完成时会发送,一般扫描过程最长为12秒
//搜索蓝牙
private void searchBluetooth() {
hasRegist = true ;
IntentFilter filter = new IntentFilter() ;
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver,filter);
if (bluetoothAdapter.isDiscovering()) {
//通过cancelDiscovery方法来取消扫描
bluetoothAdapter.cancelDiscovery();
}
datas.clear();
//通过调用BluetoothAdapter的startDiscovery方法来扫描,扫描的结果通过广播来监听
blutoothAdapter.startDiscovery() ;
}
在广播的receiver里,通过BluetoothDevice得到远程的蓝牙设备的信息:
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) { //发现了蓝牙
//得到发现的蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) ;
String itemName = device.getName() ;
String hasPaired = device.getBondState == BluetoothDevice.BOND_BONDED ?"(已配对)":"(未配对)" ;
String address = device.getAddress() ;
TBlueToothInfo info = new TBlueToothInfo() ;
info.setDeviceName(itemName + hasPaired) ;
info.setDeviceAddr(address) ;
if (!hasContainedDevice(info)) {
datas.add(info) ;
adapter.notifyDataSetChanged() ;
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
if (datas.size == 0 ) {
//没有发现任何设备
}
}
}
}
//判断扫描出的设备是不是已经存在于数据列表中了
private boolean hasContainedDevice(TBlueToothInfo info) {
for (TBlueToothInfo blueToothInfo : datas) {
if (info.getDeviceAddr.equals(blueToothInfo.getDeviceAddr())) {
return true ;
}
}
return false ;
}
注册了receiver,也自然要注销:
@Override
protected void onStop() {
super.onStop() ;
if (hasRegist) {
unregisterReceiver(receiver) ;
}
}
在receiver中,我们得到了扫描出的蓝牙设备信息,并且展示到了列表中,现在,我们设置recyclerview的item点击事件,点击配对当前设备:
@Override
public void clickItem(int position) {
//取到当前点击item的蓝牙地址,通过adapter得到远程设备
mDevice = bluetoothAdapter.getRemoteDevice(datas.get(position).getDeviceAddr()) ;
if (mDevice.getBondState() == BluetoothDevice.BOND_NONE) { //如果未配对过
IntentFilter boundFilter = new IntentFilter() ;
boundFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) ;
registerReceiver(boundReceiver,boundFilter);
//已经配对,则解除配对
pairOrConnect(true) ;
} else {
//未配对,则开始配对
pairOrConnect(false) ;
}
}
这里我们获取到远程设备的配对状态,如果是没有配对过的设备,则开始配对:
private void pairOrConnect(boolean pair) {
boolean success ;// 配对 或 解除配对是否成功
if (pair) {//未配对过的设备,开始配对
try {
Method createBound = BluetoothDevice.class.getMethod("createBond");
success = (boolean) createBoundMethod.invoke(mDevice) ;
} catch(NoSuchMethonException e) {
e.printStackTrace();
} catch(InvocationTargetException e ) {
e.printStackTrace();
} catch(IllegalAccessException e) {
e.printStackTrace();
}
} else {//已经配对过的设备,则取消配对
try {
Method removeBound = BluetoothDevice.class.getMethod("removeBound");
success = (boolean) removeBound.invoke(mDevice) ;
} catch(NoSuchMethonException e) {
e.printStackTrace();
} catch(InvocationTargetException e ) {
e.printStackTrace();
} catch(IllegalAccessException e) {
e.printStackTrace();
}
}
}
这里无论是配对还是移除配对(createBond/removeBond)都是通过反射来调用BluetoothDevice类里的方法,具体有哪些方法可用可以加直接看BluetoothDevice.class的源码。
蓝牙配对状态的改变,我们通过注册boundReceiver来监听:
private BroadcastReceiver boundReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context , Intent intent) {
String action = intent.getAction() ;
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (!mDevice.equals(device)) {//得到的设备不是刚刚点击的设备
return ;
}
switch(device.getBondState()) {//得到设备的配对状态
case BluetoothDevice.BOND_BONDING:
//配对中...
breake;
case BluetoothDevice.BOND_BONDED:
//配对成功
for (TBlueToothInfo info : datas ) {
if (info.getDeviceAddr().equals(device.getAddress())) {
String name = info.getDeviceName();
name = name.replace("未配对","已配对");
info.setDeviceName(name) ;
}
}
adapter.notifyDataSetChanged();
unregisterReceiver(boundReceiver) ;
break ;
case BluetoothDevice.BOND_NONE:
//配对成功
for (TBlueToothInfo info : datas ) {
if (info.getDeviceAddr().equals(device.getAddress())) {
String name = info.getDeviceName();
name = name.replace("未配对","已配对");
info.setDeviceName(name) ;
}
}
adapter.notifyDataSetChanged();
//注销boundReceiver
unregisterReceiver(boundReceiver) ;
break ;
default:
break;
}
}
}
}
现在,蓝牙的打开、搜索、配对和取消配对就已经全部实现了,也算是完成了蓝牙最基本的功能。完成配对后就可以开始连接并传输数据了。