在做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}.     * 

* 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


更多相关文章

  1. 暂时只会这种导航,实时显示自己的位置,,求其他更好的方法,或api
  2. Android实现图片 高斯模糊,以及图片镜像 翻转。
  3. android真机调试出现offline解决方法
  4. 阅读《Android(安卓)从入门到精通》(33)——Intent 分类
  5. Android生成keystore方法
  6. 手机蓝牙和蓝牙模块进行通信
  7. Android实现卡拉OK字幕效果方法
  8. Android创建一个Activity的方法分析
  9. android中performHapticFeedBack方法的使用

随机推荐

  1. 第十五章 消息循环模型 - 草稿
  2. Android车载方案公司,你该何去何从?
  3. Android开发签名问题
  4. [置顶] Android中的XML解析与生成——SAX
  5. 谷歌无限期推迟Android(安卓)2.1操作平台
  6. Android(安卓)studio 错误提示,英文转中文
  7. Android切近实战(二)
  8. 关于 apk文件反编译的方法(dex2jar和JD-G
  9. android手机安全问题汇总(非技术)
  10. 自动裁剪Android(安卓)ICON并保存到对应