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;
            }
        }
    }
}

现在,蓝牙的打开、搜索、配对和取消配对就已经全部实现了,也算是完成了蓝牙最基本的功能。完成配对后就可以开始连接并传输数据了。