Skip to content
ryanidev edited this page Jun 13, 2017 · 32 revisions

Do you have a general FAQ? This stuff is too technical.

Yes!

SweetBlue seems great and all but I'm still having trouble connecting and staying connected...what can I do?

There are dozens of variables involved with achieving and maintaining a stable connection, many of which are outside of SweetBlue's control. Your best best is to go through our Troubleshooting steps and see if anything helps.

Are Java Docs hosted somewhere?

http://idevicesinc.com/sweetblue/docs/api/

Does SweetBlue cleanly handle multiple device connections simultaneously?

Yes, this was one of the primary purposes for its creation.

Why does SweetBlue default to PRE-LOLLIPOP when scanning?

We made this change in version 2.51.45, because we found that the newer scanning API introduced in Lollipop simply doesn't work nearly as well as the pre-Lollipop API. Devices just weren't being found as often, and as reliably as the pre-lollipop API. You can check this issue out for more information: https://code.google.com/p/android/issues/detail?id=82463

What happens when my app is backgrounded?

If you're connected to a device the Android operating system seems to hold some kind of implicit wake lock that prevents it from going to sleep and disconnecting your peripheral. This is automatic and doesn't require any permissions or programmatic intervention.

If you're not connected to a device, the operating system will treat your app like any other. If you need your app to stay awake in order to scan then you may need to manage your own wake lock. See http://idevicesinc.com/sweetblue/docs/api/com/idevicesinc/sweetblue/BleManager.html#pushWakeLock() and http://idevicesinc.com/sweetblue/docs/api/com/idevicesinc/sweetblue/BleManager.html#popWakeLock() for helper methods that can aid you here.

What is SweetBlue's threading model?

Default behavior:

Doing multi-threading in Java can be a huge source of bugs, so we made a deliberate decision to force the API such that it can only be called from the main thread (similar to Android's View library), and operation results are posted back to the main thread through asynchronous callbacks only. In fact if you try to call most functions from other threads you will get blasted with WrongThreadError. The model should be very familiar if you have any experience with JavaScript, for example. Under the hood of course SweetBlue does some multi-threading, but this is all hidden from you.

However, as of 2.52.X, SweetBlue can (and probably should) be run on a background thread. This is achieved by setting http://idevicesinc.com/sweetblue/docs/api/com/idevicesinc/sweetblue/BleManagerConfig.html#runOnMainThread to false. This change results in better performance of the UI thread (especially on Samsungs, which love to spam logcat while scanning).

How is reconnection handled?

In order to understand some of the decisions behind reconnect logic, one must first understand that disconnects can happen very frequently on Android even under the best of conditions. You may sometimes gets disconnects every few seconds even though you can trivially reconnect immediately afterwards.

So, when a disconnect occurs a BleDevice enters a state called RECONNECTING_SHORT_TERM. What this means is that SweetBlue temporarily hides the fact that the device actually disconnected while it tries to silently reconnect for several seconds. If this silent reconnection fails, a BleDevice notifies your app code of the disconnect and enters a state called RECONNECTING_LONG_TERM. This means the device will automatically try connecting again and again until, e.g. it comes back into range. Overall by default SweetBlue is pretty aggressive about reconnecting due to how often random disconnects can occur even under the best of conditions. The short term reconnect is meant to hide the annoying transient disconnects from you, while the long term is a convenience to re-establish connection after legitimate disconnects (e.g. from going out of range) as soon as possible.

You can control the reconnect behavior through a ReconnectFilter if the defaults don’t work for your situation.

If I have a known MAC address can I avoid scanning and just connect directly?

Yes, see http://idevicesinc.com/sweetblue/docs/api/com/idevicesinc/sweetblue/BleManager.html#newDevice(java.lang.String).

What's the maximum amount of data you can write to a characteristic at a time?

Generally 20 bytes. This is a limitation imposed by the BLE specification. However, SweetBlue also has support for BLE's reliable write mechanism, which essentially breaks up writes greater than 20 bytes into individual packets where they're reassembled on the peripheral side and treated as one atomic chunk. In practice this is of limited use though because (a) it requires the firmware to implement such, and (b) doesn't usually work anyway. It's there to try though!

What's up with BleTransaction? When would I need to use this?

To be clear, there is no similar concept of a transaction in the actual underlying BLE specification - this is a SweetBlue-only construct. Transactions are simply a convenient and totally optional way to bundle a series of specialized reads and writes into one nice unit of code, and also gives a signal to SweetBlue that these reads and writes are probably important, thus giving some amount of priority to them. You typically fail a transaction (BleTransaction.fail()) when one of your reads or writes fail. On the flip side, you typically call BleTransaction.succeed() when your series of reads and/or writes complete successfully. You override [BleTransaction.onEnd()](http://idevicesinc.com/sweetblue/docs/api/com/idevicesinc/sweetblue/BleTransaction.html#onEnd(com.idevicesinc.sweetblue.BleDevice, com.idevicesinc.sweetblue.BleTransaction.EndReason)) to know when/how your transaction completes. Some examples of when you would use transactions:

  • Some companies like to make sure that only their app can connect to their peripheral. To do this you can implement an application-specific authentication handshake using a few reads and writes inside of a subclass of BleTransaction.Auth and pass an instance of this subclass to various overloads of BleDevice.connect() such as BleDevice.connect(BleTransaction.Auth).
  • Most devices need to have a characteristic or two read right after connection for user-experience purposes. For example if you're connecting to a heart-rate monitor you probably want to read the heart-rate right after connection so it appears as quickly as possible in the application's UI. SweetBlue acknowledges this common use case through BleTransaction.Init. Pass a subclass of this to various overloads of BleDevice.connect() such as BleDevice.connect(BleTransaction.Init) and the library will treat this transaction as part of the overall connection process, which conceptually makes a lot of sense for most application UI flows - that is, you're not "fully" connected until you've read some initial data from the peripheral.
  • Most devices also have a firmware update protocol that involves a bunch of writes over the course of several minutes or even hours depending on transfer speed and file size. Doing these writes inside of a subclass of BleTransaction.Ota is recommended so that SweetBlue knows a long-running transfer is occurring and can temporarily reassign resources accordingly. Use BleDevice.performOta(BleTransaction.Ota) to accomplish this.

Is BleManager a singleton?

Funny you should ask. Why yes it is. When you call BleManager.get(Context) for the first time, this is when the BleManager is actually created. Subsequent calls simply retrieve this already-created instance, no matter what Context you pass. In other words, even if you call this getter from one Activity then another, you're still getting the same actual BleManager instance. We weren't ecstatic about making this a singleton, but not doing so just clashed too much with Android's API underneath which also uses singletons.

What is the difference between CONNECTING_OVERALL and CONNECTING?

CONNECTING_OVERALL is the "master" state that encompasses CONNECTING, DISCOVERING_SERVICES, AUTHENTICATING, and INITIALIZING (and sometimes BONDING). In other words if you wrote a simple app that showed a spinner for the connection process, CONNECTING_OVERALL would probably be what you would use to show and hide the spinner. CONNECTING would probably be renamed to CONNECTING_BLE if we didn't care about backwards compatibility.

Clone this wiki locally