I have an app that successfully reads different bluetooth characteristics. It works, but only if I wait a certain time between reading a different characteristic. This time varies between 70 and 200 milliseconds and i find it very annoying. Doesn anyone else experience this problem? Or does anyone know of a way to fix this?
This is a prevalent issue, i used to a request queue and a GATT timeout in processing different requests, it solved the problem for a certain extent i should say.
Have a look at this https://git.ti.com/sensortag-20-android
Ti people has a demo implementation of a BluetoothLeService, which has request queuing, may work for you.
Related
I'm using Retrofit and OkHttpClient to build a Rest API on Android.
Some time ago, i had noticed the very first request made by the api always take way longer to process than all others... At begining i didn't care because it was an acceptable time.
But suddenly the request time jumped to 60 SECONDS
All this time is waste client side, since monitoring the server i see that the processing time takes less than 1 seconds...
I was wondering what change I made that could cause such high impact, then I realized that i changed the connection timeout of OkHttp.
I had changed the value from 10 seconds to 60 seconds just for testings...
I made some experiments setting the connectTimeout to many others values and ALWAYS the first request takes the time sighly above the timeout
Does anyone know what may cause this weird behavior? how to solve it?
PS. I needed to test the api on a desktop and this problem didnt occur, i mean it is only happening on android devices [i tried several] what is the cause?
https://medium.com/inloopx/okhttp-is-quietly-retrying-requests-is-your-api-ready-19489ef35ace
It is likely failing on the first few requests and timing out. OkHTTP is automatically retrying.
builder.retryOnConnectionFailure(false);
Try turning off the auto retry and see what happens.
https://www.reddit.com/r/gfycat/comments/5y2dkm/psa_for_android_devs_how_to_work_around_ipv6/
It is likely an ipv4 vs ipv6 problem. This code prioritizes ipv4 addressses.
You could configure an EventListener in your OkHttpClient and use that to see how the time is spent.
It may sound stupid but. I've set the timeout to 5 seconds and testing with a 3g connection it seems to be too little when in my experience it really sounds like an eternty.
What's a common use value for users not to desperate and keep the things together?
There are really no special, commonly used values for something like timeouts. A value that works for one user may not work for the other. The important thing from a UX perspective is, when the timeout does occur, the user is informed of:
A timeout has occurred.
The next appropriate action to recover from it, such as, restart the app, wait a while, contact support etc.
via unambiguous error message.
Doesn't sound stupid, but it depends on the interaction between your app and the server. Unlike a router based timeout, some routers begin their calculation when they begin to do the work (Heroku comes to mind). In this case, anything under 30 seconds is good.
I am trying to write a Bluetooth LE app that accesses a Zephyr HxM Smart heart monitor. This monitor has several Bluetooth services, but I am interested in the Battery Service, Heart Rate Service, and a Custom Service that has Activity and Peak Acceleration. There is one characteristic for each, Battery Level, (BAT), Heart Rate Measurement (HR), and Custom Measurement (CUS). The HxM updates about once per sec.
I am doing this with a Galaxy S4 with Android 4.4.
It is not working as expected from the documentation.
My initial approach was to do:
Read BAT
Set notification for HR
Set notification for CUS.
Then wait for the callbacks. Setting notification means calling
BluetoothGatt.setCharacteristicNotification(Characteristic char , boolean enabled)
(One could also do notification for BAT, however, the spec does not require this to be supported. The HxM, however, does support it.)
This didn't work. I got BAT and notifications for HR, but not CUS. If I eliminated the second step, I got notifications for CUS. I couldn't get both. (This indicates I am reading the characteristics correctly, so that is [probably] not the problem.)
I found some indications there were problems with the Bluetooth stack for Android being synchronous, but no hard documentation. I then tried the following:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then disable notification for HR, and start notification for CUS.
Get CUS, then disable notification for CUS, and start notification for HR.
And continue to loop.
I got BAT and that is all.
By trial and error, I discovered the following works:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then start notification for CUS.
Get CUS, then start notification for HR.
And continue to loop.
(Same as above but without disabling notifications.) Typically, I get a HR reading, then the CUS one within 200 ms. One can assume they are from the same update. (There are no timestamps in the data, which have to be kept short to be LE.) In reality the logic is more complicated, as timers are necessary in case expected readings don't come in. This logic is FAR more complicated (and more prone to error) than my first try, which is what the documentation seems to say is what is appropriate.
I have contacted Zephyr, and they say the HxM Smart has been extensively tested on Windows, and will do simultaneous notifications as it should. There are also indications it works as it should on iOS.
There is a further problem that I do not understand. In order to get notifications, you have to enable the Characteristics locally for notification with something like:
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG);
resSet = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
resWrite = mBluetoothGatt.writeDescriptor(descriptor);
This is a per characteristic setting, and should only need to be done once, when the characteristic is first received. Instead, I find I have to do it every time I set the notifications. It is possible this just causes a sufficient time delay for things to work. I don't know. This trial and error is taking a lot of my time. It would be nice to have a definitive statement of how it works.
I should note that for all calls that return a result, the result is true (success).
I apologize for the long statement. My question is:
I find no documentation that I have to do the things described. All indications are that you set up notifications and wait for the callbacks. Is there documentation, or is this a bug, or just a bad implementation? (Or is it my error?) I would especially like to know where is the documentation for what I have had to do.
Second, there is a further complication. I have tried to debug into the routines to see what the code is actually doing. When I get to BluetoothGatt.class, the source lines don't match what the debug stack says. I thus assume that the S4 is not using standard Android. I don't know where to go from there. It has been frustrating, and while I have something that appears to work, it is kludgy and almost certainly less robust.
Thanks for any help.
I had the same problem with writing multiple values in sequence, putting a Thread.sleep(200) in between them solved the problem (alas i should say). Maybe this helps as well with getting notifications.
Tested this on android 4.4.2 on Nexus 5. And no, 4.4 does not solve all problems...
Im probably very late to this but you should implement a queuing architecture for setting up your characteristics to send notifications. I used a similar technique to miznick in the post https://stackoverflow.com/a/18207869/3314615 and ended up just writing wrapper code for the native BLE stack since there are several apps i use BLE for. Ever since then I have had no issues receiving notifications. I agree with you that the Android BLE documentation should have some sort of information or warning about the BLE Stack not being synchronous. Frankly, i believe it should be re-written to handle synchronous write calls and just queue them.
First, you set Notification(i.e. setCharacteristicNotification and set Descriptor) for first characteristic.
And, Set notification for second characteristic in onDescriptorWrite callback function.
In my Android app, while calling a remote phone I need to keep track of the number of times the remote phone rings before it (i.e. remote phone) goes to off-hook or idle state. Googling for this topic hasn't yielded anything of much help. A brute force method could be to process the audio and count the rings -- but this seems ugly and avoidable and may not work with all carriers/phones. I'm looking for a pointer to some documented/undocumented API that Android may have to address this requirement.
Any suggestions for solution or pointers to where shall I explore will be much appreciated.
Thanks in advance,
B.Sodhi
Take a look at SIP protocol!
If you go deep enough in your Android you can have a callback, when the remote phone is received the call signal. From there you will count X seconds and is done.
Not so easy to implement as it said, but is possible. A technical man, never says it is imposible :)
I have implemented a queue service in Android that will change states based on queue and wifi/data connectivity events.
I queue transactions to be posted to a remote url. If the device has a data or wifi connection, it will iterate the queue and post data to the url until the queue is empty, or there is a disconnect event.
I can login to my app, enable airplane mode, generate data, turn airplane mode off, and the transaction are posted. No slow down, even with thousands of transactions. (I was trying to pish it a bit)
Enter: low reception!
My app slows down enormously when the 3G reception is low. (Yes, all uploading happens off the ui thread.) It seems that the cause of this slow down has to do with the post to the server taking a very long time to happen and sometimes just failing.
My question is, how can I solve this? Check for signal quality? Poll a known address? How do other apps, such as Gmail solve this? This must be a common scenario!
Well if you could potentially have thousands of tasks that all need to be executed, then surely they should be managed. Have you thought about implementing your own ThreadPoolExecutor? The documentation is very good and the class is easy to understand, but if you need examples try these sites:
http://www.javamex.com/tutorials/threads/ThreadPoolExecutor.shtml
http://javabeanz.wordpress.com/2010/02/19/threadpoolexecutor-basics/
The benefit of this is that you can limit the maximum number of threads you are spawning, so you shouldn't get a system-wide slow down if you limit your thread count to a reasonable number (For Android I'd recommend no more than 20).
May be do some fine-tuning of socket and conenction timeout? Thus, if your connection is slow and stalled, timeout will occur and transmission will fail.
After connection/sending is failed you can retry transmission later or do something else.
To adjust timeouts you can use the following code:
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 30 * 1000);
HttpConnectionParams.setSoTimeout(httpParameters, 15 * 1000);
HttpClient client = DefaultHttpClient(httpParameters);
// use client...
We have similar situation for our application. We have considered signal issues to be a reality and one that can happen any time. One of the point that we follow is not to remove any content from device unless we get a functional confirmation from server and just base on http status code.As in the slow network or the cases where we can lose signal suddenly, while we may have posted our content, there were many cases where data was received only partially. And so we decided to let server know device by some manner [result through some http get based request calls made by device] that content has been received.
More than performance or checking the network, the question that you asked, we needed such behavior for our application robustness.
You should check out using HTTP Range headers, for example like here.
The server should write payload to disk while reading, and handle disconnects. The client cannot know how many bytes payload actually reached the server, so it needs to sync up with the server every time there has been a network error. Dont forget to handle battery and user issues too ;-)
If you want to wait for a better signal, perhaps the SignalStrength class, with its getCdmaDbm, getEvdoDbm, and getGsmSignalStrength methods, is what you are looking for.
Check out this:
http://www.youtube.com/watch?v=PwC1OlJo5VM#!
advanced coding tips and tricks, bandwidth-saving techniques, implementation patterns, exposure to some of the lesser-known API features, and insight into how to minimize battery drain by ensuring your app is a good citizen on the carrier network.