在做Android BLE的应用程序时,我们发出广播数据是调用BluetoothLeAdvertiser的startAdvertising方法,如下所示: mBluetoothLeAdvertiser.startAdvertising(advertiseSettings, advertiseData, myAdvertiseCallback); 那么我打算写的BLE总结之源码篇就以此为线索来分析Android BLE FrameWork方面的东西。 public void startAdvertising(AdvertiseSettings settings, AdvertiseData advertiseData, final AdvertiseCallback callback) { startAdvertising(settings, advertiseData, null, callback); } public void startAdvertising(AdvertiseSettings settings, AdvertiseData advertiseData, AdvertiseData scanResponse, final AdvertiseCallback callback) { synchronized (mLeAdvertisers) { //该check只是检查mBluetoothAdater是否为null和其状态是否为State_ON BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } if (!mBluetoothAdapter.isMultipleAdvertisementSupported() && !mBluetoothAdapter.isPeripheralModeSupported()) {//是否支持广播和作为外围设备 postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED); return; } boolean isConnectable = settings.isConnectable(); if (totalBytes(advertiseData, isConnectable) > MAX_ADVERTISING_DATA_BYTES || totalBytes(scanResponse, false) > MAX_ADVERTISING_DATA_BYTES) { postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); return; } if (mLeAdvertisers.containsKey(callback)) { postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED); return; } IBluetoothGatt gatt; try { gatt = mBluetoothManager.getBluetoothGatt(); } catch (RemoteException e) { Log.e(TAG, "Failed to get Bluetooth gatt - ", e); postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); return; } AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData, scanResponse, settings, gatt); wrapper.startRegisteration(); } } 大家可以看到在startAdvertising内部,首先经过了一系列的判断,然后包装了一个叫作AdvertiseCallbackWrapper的类来做发广播数据的行为。 我们先看一下startAdvertising内部都是做了哪些判断: 1.判断蓝牙是否已经打开,否则抛出异常。 2.判断回调callback是否为空 3.判断当前设备是否支持广播数据和作为外围设备 4.判断广播数据包的长度是否超过了31字节 5.判断广播是否已经开始 经过了这5步初步的判断,下面来到了最重要的地方,mBluetoothManager.getBluetoothGatt();获取一个引用,最终的发送广播和停止广播都是通过这个引用来进行实现的。这里不进行展开,因为本文主要是对BluetoothLeAdvertiser的解读。 下面我们就来看看刚才提到的AdvertiseCallbackWrapper,代码如下: /** * Bluetooth GATT interface callbacks for advertising. */ private class AdvertiseCallbackWrapper extends BluetoothGattCallbackWrapper { private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000; private final AdvertiseCallback mAdvertiseCallback; private final AdvertiseData mAdvertisement; private final AdvertiseData mScanResponse; private final AdvertiseSettings mSettings; private final IBluetoothGatt mBluetoothGatt; // mClientIf 0: not registered // -1: advertise stopped or registration timeout // >0: registered and advertising started private int mClientIf; private boolean mIsAdvertising = false; public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback, AdvertiseData advertiseData, AdvertiseData scanResponse, AdvertiseSettings settings, IBluetoothGatt bluetoothGatt) { mAdvertiseCallback = advertiseCallback; mAdvertisement = advertiseData; mScanResponse = scanResponse; mSettings = settings; mBluetoothGatt = bluetoothGatt; mClientIf = 0; } public void startRegisteration() { synchronized (this) { if (mClientIf == -1) return;//这个就不解释了 try { UUID uuid = UUID.randomUUID(); mBluetoothGatt.registerClient(new ParcelUuid(uuid), this);//注册 wait(LE_CALLBACK_TIMEOUT_MILLIS);//等待2秒,在过程中会依次回调onClientRegistered和onMultiAdvertiseCallback } catch (InterruptedException | RemoteException e) { Log.e(TAG, "Failed to start registeration", e); } //注册成功并且广播成功,加入广播缓存,以callback为key的Hashmap,callback为用户自己定义的Callback if (mClientIf > 0 && mIsAdvertising) { mLeAdvertisers.put(mAdvertiseCallback, this); } else if (mClientIf <= 0) {//注册失败 // Registration timeout, reset mClientIf to -1 so no subsequent operations can // proceed. if (mClientIf == 0) mClientIf = -1; // Post internal error if registration failed. postStartFailure(mAdvertiseCallback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); } else {//注册成功但广播开启失败 // Unregister application if it's already registered but advertise failed. try { mBluetoothGatt.unregisterClient(mClientIf); mClientIf = -1; } catch (RemoteException e) { Log.e(TAG, "remote exception when unregistering", e); } } } } public void stopAdvertising() { synchronized (this) { try { mBluetoothGatt.stopMultiAdvertising(mClientIf); wait(LE_CALLBACK_TIMEOUT_MILLIS); } catch (InterruptedException | RemoteException e) { Log.e(TAG, "Failed to stop advertising", e); } // Advertise callback should have been removed from LeAdvertisers when // onMultiAdvertiseCallback was called. In case onMultiAdvertiseCallback is never // invoked and wait timeout expires, remove callback here. if (mLeAdvertisers.containsKey(mAdvertiseCallback)) { mLeAdvertisers.remove(mAdvertiseCallback); } } } /** * Application interface registered - app is ready to go */ @Override public void onClientRegistered(int status, int clientIf) { Log.d(TAG, "onClientRegistered() - status=" + status + " clientIf=" + clientIf); synchronized (this) { if (status == BluetoothGatt.GATT_SUCCESS) { try { if (mClientIf == -1) {//在2秒内未完成注册,超时 // Registration succeeds after timeout, unregister client. mBluetoothGatt.unregisterClient(clientIf); } else {//完成注册,并开始广播 mClientIf = clientIf; mBluetoothGatt.startMultiAdvertising(mClientIf, mAdvertisement, mScanResponse, mSettings); } return; } catch (RemoteException e) { Log.e(TAG, "failed to start advertising", e); } } // Registration failed. mClientIf = -1; notifyAll(); } } @Override public void onMultiAdvertiseCallback(int status, boolean isStart, AdvertiseSettings settings) { synchronized (this) { if (isStart) {//广播成功时的回调 if (status == AdvertiseCallback.ADVERTISE_SUCCESS) { // Start success mIsAdvertising = true; postStartSuccess(mAdvertiseCallback, settings); } else { // Start failure. postStartFailure(mAdvertiseCallback, status); } } else {//stop 时的回调,用来反注册和清除缓存的callback // unregister client for stop. try { mBluetoothGatt.unregisterClient(mClientIf); mClientIf = -1; mIsAdvertising = false; mLeAdvertisers.remove(mAdvertiseCallback); } catch (RemoteException e) { Log.e(TAG, "remote exception when unregistering", e); } } notifyAll(); } } } private void postStartFailure(final AdvertiseCallback callback, final int error) { mHandler.post(new Runnable() { @Override public void run() { callback.onStartFailure(error); } }); } private void postStartSuccess(final AdvertiseCallback callback, final AdvertiseSettings settings) { mHandler.post(new Runnable() { @Override public void run() { callback.onStartSuccess(settings); } }); } AdvertiseCallbackWrapper的成员变量mClientIf非常重要,在广播发送和停止的过程中起着重要的作用。这里先简单的记住该属性的以下特征: mClientIf=0——>未注册 mClinetIf=-1——>广播停止或注册超时 mClientIf>0——>已注册并且已经广播成功 mClientIf默认值为0 这时我们追踪到startRegisteration这个方法了,该方法里面调用了registerClient方法,经过IPC通信后会回调到onClientRegistered方法,继续调用到了startMultiAdvertising方法,接着触发onMultiAdvertiseCallback,成功发送广播后,将该AdvertiseCallbackWrapper对象加入mLeAdvertisers。 这里我们需要注意和了解以下几点: 1.在调用startRegisteration的2秒的时间内,如果没有注册成功且广播成功,这次广播数据的行为均为失败。 2.即使2秒之后onClientRegistered回调,也将视为注册未成功,并进行解注册操作。 startAdvertising方法就到这,至于更底层的细节后续的文章会展开,下面我们看一下其对应的stopAdvertising方法 /** * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in * {@link BluetoothLeAdvertiser#startAdvertising}. * <p> * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. * * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop. */ public void stopAdvertising(final AdvertiseCallback callback) { synchronized (mLeAdvertisers) { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback); if (wrapper == null) return; wrapper.stopAdvertising(); } } 大家可以看到,stopAdvertising方法内部是调用AdvertiseCallbackWrapper.stopAdvertising方法。这里必须注意stopAdvertising方法的callback必须和start时传入的callback参数是同一个。否则在mLeAdvertisers缓存里是找不到相应的AdvertiseCallbackWrapper的实例的,就无法正常停止广播。 转载请注明:http://blog.csdn.net/android_jiangjun/article/details/77946857