• android5.0 BLE 蓝牙4.0+浅析demo搜索(一)


    作者:Bgwan
    链接:https://zhuanlan.zhihu.com/p/23341414
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    作者:Bgwan 莳萝花
    链接:android BLE 蓝牙4.0+浅析(一) - Android开发 - 知乎专栏
    来源:知乎
    著作权归作者所有,转载请联系作者获得授权。

    android BLE 蓝牙4.0+浅析(一)

    Android 4.3 (API Level 18) introduces built-in platform support for Bluetooth Low Energy in the central roleand provides APIs that apps can use to discover devices, query for services, and read/write characteristics.

    +代表蓝牙更高版本,

    本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,是用不了蓝牙4.0的,我们通常可以加一个判断。

    首先:操作蓝牙,我们需要在AndroidMainfest.xml中配置,如下权限,

    <!--蓝牙权限-->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true"></uses-feature>
    

    说明:hardware是,在底判断是否支持,蓝牙,admin是超级权限,根据用户需求不同加入不同的权限,

    蓝牙SDK版本判断,如下代码:

    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
        Toast.makeText(this, "当前版本SDK" + Build.VERSION.SDK_INT + "< Android5.0不支持蓝牙", Toast.LENGTH_SHORT).show();
    mText.setText("当前版本" + Build.VERSION.SDK_INT + "< Android5.0不支持蓝牙");
    return;
    }
    

    1,打开蓝牙,蓝牙状态等操作,以及是否支持蓝牙BLE

    // Use this check to determine whether BLE is supported on the device. Then
    // you can selectively disable BLE-related features.
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
    mText.setText(R.string.ble_not_supported);
    return;
    }
    // Initializes Bluetooth adapter.
    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    //需要时再初始化
    mHandler = new Handler();
    mProgress = new ProgressDialog(NewActivity.this);
    

    2,如果蓝牙没有打开,我们需要打开蓝牙,打开蓝牙有两种方式,但是建议给用户显示的方式打开,因为用户需要知道这些权限,不然你这个就是牛氓行为。隐式打开为:

    mBluetoothAdapter.enable();
    

    ,下面的代码为显示的打开方式。

    / Ensures Bluetooth is available on the device and it is enabled. If not,
    // displays a dialog requesting user permission to enable Bluetooth.
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        Toast.makeText(this, "蓝牙正在打开,建议允许应用操作", Toast.LENGTH_SHORT).show();
    }
    

    3,搜索蓝牙操作。

    如果蓝牙都已经打开正常,则可以进行搜索周围蓝牙设备的操作,这里记住,不只是手机中的蓝牙,任何外设都可以。顺带,我们查看android SDK会发现bluetooth包下面多了le.这是android 蓝牙4.2以后新加入的操作蓝牙的包,但是谷歌为了兼容以前的版本

    mBluetoothAdapter.startLeScan(mLeScanCallback);
    

    这个方法还是可以使用,这里我们使用le。包下面最新的搜索蓝牙的功能,如下:

     //最新写法。蓝牙打开才执行
        if (mBluetoothAdapter.isEnabled()) {
    mProgress.setMessage("正在搜索周围设备...");
    mProgress.setCancelable(false);
    mProgress.show();
    newtext.setText("蓝牙已经打开,关闭蓝牙请在设置中设置");
    mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
    // Initializes list view adapter.
            mLeDeviceListAdapter = new LeDeviceListAdapter();
    listView.setAdapter(mLeDeviceListAdapter);
    //显示dialog
            new Thread(new Runnable() {
    @Override
                public void run() {
    try {
                        Thread.sleep(3000);
    if (mProgress != null) {
    mProgress.dismiss();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    mLeDeviceListAdapter.clearDevice();
            scanLeDevice(true);
        }
    }
    

    scanLeDevice是对方法的封装,这里主要是调用bluetoothlescanner的starscan方法,该方法可以传递两个参数,这里先讨论传递mScanCallback这是一个扫描结果的回掉接口;当然这里操作也应该放到子线程中去处理。

    mBluetoothLeScanner.startScan(mScanCallback);//新
    

    具体的scanLeDevice()方法如下:

    private void scanLeDevice(final boolean enable) {
    if (enable) {
    // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
    @Override
                public void run() {
    mScanning = false;
    mBluetoothLeScanner.stopScan(mScanCallback);
                    invalidateOptionsMenu();
                }
            }, SCAN_PERIOD);
    mScanning = true;
    mBluetoothLeScanner.startScan(mScanCallback);//新
        } else {
    mScanning = false;
    mBluetoothLeScanner.stopScan(mScanCallback);
        }
        invalidateOptionsMenu();
    }
    

    4,以上我们就开启了蓝牙的搜索,功能,然后会触发mScanCallback进行结果的监听。主要监听里面的三个方法,onScanResult,onBatchScanResults,onScanFailed,搜索到结果以后,我们需要对它进行解析,代码里面都注释得很清楚


    // Device scan callback.
        private ScanCallback mScanCallback = new ScanCallback() {
    @Override
            public void onScanResult(int callbackType, ScanResult result) {
    super.onScanResult(callbackType, result);
    if (result == null || result.getDevice() == null
                        || TextUtils.isEmpty(result.getDevice().getName())) {
    mText.setText("没有搜索到蓝牙设备");
    //                return;
                }
    //如果是外设则可能存在没有ServiceUuids
    //            builder.append("/n").append(
    //                    new String(result.getScanRecord().getServiceData(
    //                            result.getScanRecord().getServiceUuids().get(0)),
    //                            Charset.forName("UTF-8")));
    
                BluetoothDevice device = result.getDevice();
                Log.d(TAG, "Device name: " + device.getName());
                Log.d(TAG, "Device address: " + device.getAddress());
                Log.d(TAG, "Device service UUIDs: " + device.getUuids());
    if (builder.toString().contains(device.getName())) {
                } else {
    builder.append("
    " + device.getName() + "&" + device.getAddress() + "
    ");
                }
                ScanRecord record = result.getScanRecord();
                Log.d(TAG, "Record advertise flags: 0x" + Integer.toHexString(record.getAdvertiseFlags()));
                Log.d(TAG, "Record Tx power level: " + record.getTxPowerLevel());
                Log.d(TAG, "Record device name: " + record.getDeviceName());
                Log.d(TAG, "Record service UUIDs: " + record.getServiceUuids());
                Log.d(TAG, "Record service data: " + record.getServiceData());
    
    mLeDeviceListAdapter.addDevice(device);
    mLeDeviceListAdapter.notifyDataSetChanged();
    
    mText.setText("搜索结果,builder:" + builder.toString());
            }
    
    @Override
            public void onBatchScanResults(List<ScanResult> results) {
    super.onBatchScanResults(results);
    for (ScanResult result : results) {
                    Toast.makeText(getApplicationContext(), "result:" + result.getDevice().getAddress(), Toast.LENGTH_SHORT).show();
                }
            }
    
    @Override
            public void onScanFailed(int errorCode) {
    super.onScanFailed(errorCode);
    mText.setText("搜索蓝牙失败 errorCode:" + errorCode);
    
            }
        };
    

    这里我自己对搜索的结果操作为,

    mLeDeviceListAdapter.addDevice(device);
    

    加入到mLeDeviceListAdapter中去,这是一个listview的适配器,

    5,蓝牙列表,结果显示的适配器代码,很简单,如下面。

    // Adapter for holding devices found through scanning.
    private class LeDeviceListAdapter extends BaseAdapter {
    private ArrayList<BluetoothDevice> mLeDevices;
    private LayoutInflater mInflator;
    
    public LeDeviceListAdapter() {
    super();
    mLeDevices = new ArrayList<BluetoothDevice>();
    mInflator = NewActivity.this.getLayoutInflater();
        }
    
    public void addDevice(BluetoothDevice device) {
    if (!mLeDevices.contains(device)) {
    mLeDevices.add(device);
            }
        }
    
    public void clearDevice() {
    if (mLeDevices.size() > 0) {
    mLeDevices.clear();
            }
        }
    
    public BluetoothDevice getDevice(int position) {
    return mLeDevices.get(position);
        }
    
    public void clear() {
    mLeDevices.clear();
        }
    
    @Override
        public int getCount() {
    return mLeDevices.size();
        }
    
    @Override
        public Object getItem(int i) {
    return mLeDevices.get(i);
        }
    
    @Override
        public long getItemId(int i) {
    return i;
        }
    
    @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            DeviceScanActivity.ViewHolder viewHolder;
    // General ListView optimization code.
            if (view == null) {
                view = mInflator.inflate(R.layout.listitem_device, null);
                viewHolder = new DeviceScanActivity.ViewHolder();
                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
                view.setTag(viewHolder);
            } else {
                viewHolder = (DeviceScanActivity.ViewHolder) view.getTag();
            }
    
            BluetoothDevice device = mLeDevices.get(i);
    final String deviceName = device.getName();
    if (deviceName != null && deviceName.length() > 0)
                viewHolder.deviceName.setText(deviceName);
    else
                viewHolder.deviceName.setText(R.string.unknown_device);
            viewHolder.deviceAddress.setText(device.getAddress());
    
    return view;
        }
    }
    

    以上就是全部代码,下面文章,会从源码的角度分析,最新的开启,蓝牙和以前版本的对比,方便理解,在以后的文章会讲解如何连接嵌入式的蓝牙设备进行数据的传送。当然这里会由浅到深的体现出来。

  • 相关阅读:
    IOS创建Button简单实例
    IOSActionSheet、AlertView、Slider、Switch的简单使用
    IOS翻转注意
    [教程]iOS 4 开发的好东西 (资料)url
    Proxy和Decorator模式
    Using JNDI connecting DB
    影片“One Day”,还不错
    Minabased TCP server examples
    MySQL vs. Oracle on sequence
    Java DB and JDBC(Embedded Derby)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6419239.html
Copyright © 2020-2023  润新知