Android BLE: onCharacteristicRead() appears to be blocked by thread - java

I'm implementing a series of characteristic reads against a BLE device. Because readCharacteristic() executes asynchronously, and because we have to wait until it completes before issuing another "read" call, I used a lock to wait() and then in 'onCharacteristicRead() I notify() the lock to get things going again.
When I wait() after calling readCharacteristic(), I never get a call to onCharacteristicRead(). If I don't wait(), then I do get a call to onCharacteristicRead() and the correct value is reported.
Here is the relevant code that seems to block the callback to onCharacteristicRead():
private void doRead() {
//....internal accounting stuff up here....
characteristic = mGatt.getService(mCurrServiceUUID).getCharacteristic(mCurrCharacteristicUUID);
isReading = mGatt.readCharacteristic(characteristic);
showToast("Is reading in progress? " + isReading);
showToast("On thread: " + Thread.currentThread().getName());
// Wait for read to complete before continuing.
while (isReading) {
synchronized (readLock) {
try {
readLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
showToast("onCharacteristicRead()");
showToast("On thread: " + Thread.currentThread().getName());
byte[] value = characteristic.getValue();
StringBuilder sb = new StringBuilder();
for (byte b : value) {
sb.append(String.format("%02X", b));
}
showToast("Read characteristic value: " + sb.toString());
synchronized (readLock) {
isReading = false;
readLock.notifyAll();
}
}
If I simply remove the while() statement above, I successfully get the read callback. Of course, that prevents me from waiting to do further reads, so I can't move forward without waiting.
Given that the readCharacteristic() is asynchronous, why would execution of the calling thread have anything to do with the ability to actually do the read, or the ability to call the callback?
To make things more confusing, I show a toast which identifies the thread when I call readCharacteristic(), as well as when onCharacteristicRead() is invoked. These 2 threads have different names. I thought that maybe the callback was being invoked on the calling thread for some reason, but that doesn't appear to be the case. So what is going on here with the threading?

The problem here appears to be an obscure issue with threading and it can't be seen in my original post because I didn't post enough of the call history to see it. I will explain what I found here in case it effects someone else.
The full call history leading to my problem went something like this:
Start Le Scan
Find device I care about
Connect to the device's GATT server (which returns a GATT client, and where I provide a BluetoothGattCallback for all the async communication calls)
Tell the GATT client to discoverServices()
A moment later, the BLE system invokes my callback's onServicesDiscovered()
Now I'm ready to start reading characteristics because the service data is loaded, so this is where I invoke that doRead() method in my original post
Tell the GATT client to readCharacteristic()
Go to sleep until the read is done
---- This is where deadlock occurs, but its supposed to:
A moment later, the BLE system invokes my callbacck's onCharacteristicRead()
Notify all waiting threads
Go back to step 7 and repeat
First Mistake:
Originally my onServicesDiscovered() method looked like this:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
doRead();
}
When doRead() executes, it is going to sleep and therefore block execution. This prevents the callback method from finishing and apparently gunks up the entire BLE communicaiton system.
Second Mistake:
Once I realized the above issue, I changed the method to the following:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
new Thread(new Runnable() {
#Override
public void run() {
doRead();
}
).start();
}
As far as I can tell, the above version of the method should work. I'm creating a new thread on which to run doRead(), so sleeping in doRead() should not have any impact on the BLE thread. But it does! This change had no impact.
----------- Edit Note --------------
After posting this, I really couldn't rationalize why the above anonymous thread wouldn't work. So I tried it again, and this time it did work. Not sure what went wrong the first time, maybe I forgot to call start() on the thread or something...
--------- End Edit Note ------------
The Solution:
Finally, on a whim, I decided to create a background HandlerThread when my class gets instantiated (instead of spinning up an anonymous Thread in onServicesDiscovered()). The method now looks like this:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
mBackgroundHandler.post(new Runnable() {
#Override
public void run() {
doRead();
}
).start();
}
The above version of the method works. The call to doRead() successfully iterates over each characteristic as the previous one is read.

I have solved this problem by adding the following code
#Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
new Thread(new Runnable() {
#Override
public void run() {
gatt.readCharacteristic(characteristic);
}
}).start();
}

Related

How to stop/interrupt running thread from another method?

I am a total beginner to android and Java development, and I am currently trying to make a metronome.
The first problem I encountered after getting the sound playback to work, is that whenever the metronome played the app would stop responding - that's when I learned about threads and how I should use a new thread for my audio playback.
Creating a new thread helped and now the app runs fine, but I can't get the thread to stop/interrupt. I've read maybe 50 articles already about threads and interrupts and I can't figure it out.
Here is my 'Player' class code, which I've mostly copied from another Stack Overflow post (I have tried countless other ways and variations and none worked):
package com.example.t.firstapp;
import android.util.Log;
public class Player implements Runnable {
Thread backgroundThread;
Metronome m;
public void start() {
if (backgroundThread == null) {
backgroundThread = new Thread(this);
m = new Metronome();
backgroundThread.start();
}
}
public void stop() {
if (backgroundThread != null) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
}
Log.i("b", "Thread stopping.");
throw new InterruptedException(); // ???
} catch (InterruptedException ex) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("c", "Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
}
Note the line marked with "???". I added that one myself because otherwise the "catch (InterruptedException ex)" returned an error.
Here is the relevant code from my MainActivity class:
public class MainActivity extends AppCompatActivity {
...
public Player p;
...
public void play() {
p = new Player();
p.start();
}
public void stop() {
p.stop();
}
}
Calling p.stop(); from within the method 'stop' doesn't actually do anything. This is where I get stuck. If I call p.stop() immediately after I start the thread, like this:
public void play() {
p = new Player();
p.start();
p.stop();
}
Then it works, and I see all of the relevant log messages from the Player class. Why doesn't p.stop() work when I call it from my 'stop' method? Is it because I am calling it from a different method, or is it because I am not calling it immediately?
Any help would be greatly appreciated since this is extremely frustrating. I have been studying and practicing Android development for only a week now, but I haven't done anything over the last 5 days but try to solve this problem. Thanks
You misunderstood the concept of interruption. Interupting is not some magical way of forcing the thread to stop, rather it will only work for methods that have interruption support - like sleeping.
Take a look at the Thread#interrupt() API, where it lists interrupt supported methods:
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
You can nicely implement your own methods with interrupt support, by contantly checking for the interrupt status.
Now let's see how we can solve your problem.
According to your comment, m.play() does not return, meaning, once m.play() is called, the while never checks if the thread has been interrupted; in turn it will never stop, since m.play() isn't implemented to support interrupts. This should also explain why the compiler complains that nobody throws an InterruptedException. (The reason it worked if interrupted immediately, is that the interrupt status is changed before it reaches the while... Think of it.)
Now, I assume that, if you will call m.stop(), m.play() will return, successfully rechecking for thread interruption. That's why it worked, as mentioned in comment.
But look, there's no real use of interrupting the thread - since all you have to do is call m.stop() and release the m.play(), just play and wait to return - which means stop has been called. Same to the while loop, drop it all the way.
public void run() {
Log.i("a", "Thread starting.");
m.play(); // blocks till stopped from some other thread...
Log.i("b", "Thread stopping.");
Log.i("c", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
One case where I may see a use of the while and interrupt, if m.play() may return earlier than by calling m.stop() (say, by some exception), and you want to restart the metronome until stop is called; then a loop may be on the rescue, and interrupt may signal that it was actually stopped by calling m.stop().
public void run() {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
if(!backgroundThread.isInterrupted())
Log.i("b", "Stopped by exception, restarting....");
}
Log.i("c", "Thread stopping.");
Log.i("d", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}

How return a result of my method executed in thread?

I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}

Java thread doesn't stop/interrupt

I'm trying to terminate a thread but it doesn't interrupt or stop. All of this are part of controller of a software called Webots. I use this to simulate a multi robot system. In the controller of each robot, I start a thread which receive messages through robots receivers. This thread must start at first, and terminate when simulation ends.
The run method for this thread look like this:
public void run() {
while (true)
{
String M = recieveMessage();
char[] chars = M.toCharArray();
if(chars[0]==robotName||chars[0]=='0')
messages.add(M);
}
}
In the main controller I have code that look like this:
MessageThread MT = new MessageThread(messages, receiver,getName());
MT.start();
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(25); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(messages.get(messages.size()-1));
}
MT.interrupt();//MT = null;
System.out.println(MT.interrupted());
It's not important what I do in my main controller, so don't judge it. For example, messages is an ArrayList. It's like a buffer which MT put messages in and the main thread reads from. I use it because the receiver and emitter are not synchronized.
If I call interrupt() or MT = null but interrupted() it returns false and MT continues to run. Is there anything wrong in my code?
I read some topics like:
http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
How do you kill a Thread in Java?
interrupt() doesn't work
Java: How interrupt/stop a thread?
and so on but I couldn't find any useful answer.
Edit
Thanks everyone, I've made changes to my code. I added this to the MessageThread class:
private volatile boolean isRunning = true;
Then I used while(isRunning) instead of while(true) and I added
public void kill()
{
isRunning = false;
}
and called MT.kill() instead of MT.interrupt().
It worked but I couldn't find out what's wrong with interrupt(). I read the link which #ExtremeCoders recommended. However, I'm still confused. It says "a thread must support its own interruption". So do I have to overwrite the interrupt() method? I can't call interrupt to terminate a thread?
Thanks again.
Interrupting a thread just sets a flag on the thread. If the thread never checks the flag, it won't respond. By creating your own boolean member, you've duplicated that functionality unnecessarily.
Here's the general pattern for what you are trying to do:
#Override
public void run() {
while(!Thread.interrupted() {
/* Do something. */
}
Thread.currentThread().interrupt();
}
This will allow you to call MT.interrupt() as you expected. It's better than creating your own flag and custom method to set it: you can use your Runnable task with high-level tools like ExecutorService and cancellation will work because you used the standard API; same is true for interruption of an entire ThreadGroup.
Calling Thread.interrupted() clears the interruption status of a thread; we set it by calling Thread.currentThread().interrupt(), the status is set again so that callers of run() can detect the interrupted state. This might not always be desirable however.

Java: Calling method from threads one after another

I have class Server and subclass ClientThread. ClientThread has methods receive() and broadcast(String[] msg) used to receive and send messages from/to clients connected to server.
Scheme:
public class Server extends Thread {
private ArrayList<ClientThread> clientThreads;
class ClientThread extends Thread {
public void broadcast(String[] msg) {...}
public void receive() {
...
if (msg.equals("CHANGED")) {
resumeOthers();
}
public void suspendOthers() {
for (ClientThread c: clientThreads)
if (c!=this)
try {
c.wait();
} catch (InterruptedException e) {}
}
public void resumeOthers() {
for (ClientThread c: clientThreads)
if (c!=this)
c.notify();
}
}
public void run() {
...
cmd = new String[1];
cmd[0] = "PROMPTCHANGE";
for (ClientThread currPlayer: clientThreads) {
currPlayer.broadcast(cmd);
currPlayer.suspendOthers();
}
}
}
Now, I would like to make this ClientThreads work one after another, like this:
1. ClientThread number 1 is calling method broadcast.
Now any other ClientThread existing is freezed
(they are stored in ArrayList on Server)
2. Client (another class) replies with a message that is being caught by receive()
Now this thread is freezed, and the next one starts running
Unfortunately, my approach doesn't work.
Could somebody explain me in details how to achieve that?
by calling Object.wait(), you are are suspending the CALLING thread, not the thread that this object happens to be.
so in effect, you are doing a loop that blocks the calling thread N times, definitely not what you intended.
in order to pause a thread, you need to have IT wait on an objet, or have it block entering a synchronized block (or use Thread.sleep(), but usually its not a good solution).
in other words, the client threads need to call wait, not the calling thread.
One addition:
it seems you are new to Java threading and synchronization, I strongly suggest that you read about it before attempting this.
Google around for some docs on the subject.
here is something to get you started:
http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
It's not clear how the sequence of execution works.
Anyway, as already said by previous answers, calling x.wait() on a Object makes the current thread block on object x. Moreover, in order to call wait() and notify(), you first have to synchronize on that object, AND, when you call wait(), you should do it in a loop, checking for an external condition, because spurious wakeups can happen.
So, the correct pattern should be something like:
void waitForCondition() {
synchronized (lockObject) {
while (!condition) {
lockObject.wait();
}
}
}
void setCondition() {
synchronized (lockObject) {
condition = true;
lockObject.notify(); //or .notifyAll()
}
}
If you want to make the threads run one after another, try http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html

Clever asynchronous repaint in Java

I have a use-case coming from a GUI problem I would like to submit to your sagacity.
Use case
I have a GUI that displays a computation result depending on some parameters the user set in a GUI. For instance, when the user moves a slider, several events are fired, that all trigger a new computation. When the user adjust the slider value from A to B, a dozens of events are fired.
But the computation can take up to several seconds, whereas the slider adjustment can fire an event every few 100 ms.
How to write a proper Thread that would listen to these events, and kind of filter them so that the repaint of the results is lively? Ideally you would like something like
start a new computation as soon as first change event is received;
cancel the first computation if a new event is received, and start a new one with the new parameters;
but ensure that the last event will not be lost, because the last completed computation needs to be the one with last updated parameters.
What I have tried
A friend of mine (A. Cardona) proposed this low level approach of an Updater thread that prevents too many events to trigger a computation. I copy-paste it here (GPL):
He puts this in a class that extends Thread:
public void doUpdate() {
if (isInterrupted())
return;
synchronized (this) {
request++;
notify();
}
}
public void quit() {
interrupt();
synchronized (this) {
notify();
}
}
public void run() {
while (!isInterrupted()) {
try {
final long r;
synchronized (this) {
r = request;
}
// Call refreshable update from this thread
if (r > 0)
refresh(); // Will trigger re-computation
synchronized (this) {
if (r == request) {
request = 0; // reset
wait();
}
// else loop through to update again
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void refresh() {
// Execute computation and paint it
...
}
Every-time an event is sent by the GUI stating that parameters have been changed, we call updater.doUpdate(). This causes the method refresh() to be called much less.
But I have no control on this.
Another way?
I was wondering if there is another way to do that, that would use the jaca.concurrent classes. But I could not sort in the Executors framework what would be the one I should start with.
Does any of you have some experience with a similar use case?
Thanks
If you're using Swing, the SwingWorker provides capabilities for this, and you don't have to deal with the thread pool yourself.
Fire off a SwingWorker for each request. If a new request comes in and the worker is not done, you can cancel() it, and just start a new SwingWorker. Regarding what the other poster said, I don't think publish() and process() are what you are looking for (although they are also very useful), since they are meant for a case where the worker might fire off events faster than the GUI can process it.
ThingyWorker worker;
public void actionPerformed(ActionEvent e) {
if( worker != null ) worker.cancel();
worker = new ThingyWorker();
worker.execute();
}
class ThingyWorker extends SwingWorker<YOURCLASS, Object> {
#Override protected YOURCLASS doInBackground() throws Exception {
return doSomeComputation(); // Should be interruptible
}
#Override protected void done() {
worker = null; // Reset the reference to worker
YOURCLASS data;
try {
data = get();
} catch (Exception e) {
// May be InterruptedException or ExecutionException
e.printStackTrace();
return;
}
// Do something with data
}
}
Both the action and the done() method are executed on the same thread, so they can effectively check the reference to whether there is an existing worker.
Note that effectively this is doing the same thing that allows a GUI to cancel an existing operation, except the cancel is done automatically when a new request is fired.
I would provide a further degree of disconnect between the GUI and the controls by using a queue.
If you use a BlockingQueue between the two processes. Whenever the controls change you can post the new settings to the queue.
Your graphics component can read the queue whenever it likes and act on the arriving events or discard them as necessary.
I would look into SwingWorker.publish() (http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html)
Publish allows the background thread of a SwingWorker object to cause calls to the process() method, but not every publish() call results in a process() call. If multiple process calls are made before process() returns and can be called again, SwingWorker concatenates the parameters used for multiple publish calls into one call to process.
I had a progress dialog which displayed files being processed; the files were processed faster than the UI could keep up with them, and I didn't want the processing to slow down to display the file names; I used this and had process display only the final filename sent to process(); all I wanted in this case was to indicate to the user where the current processing was, they weren't going to read all the filenames anyway. My UI worked very smoothly with this.
Take a look at the implementation of javax.swing.SwingWorker (source code in the Java JDK),
with a focus on the handshaking between two methods: publish and process.
These won't be directly applicable, as-is, to your problem - however they demonstrate how you might queue (publish) updates to a worker thread and then service them in your worker thread (process).
Since you only need the last work request, you don't even need a queue for your situation: keep only the last work request. Sample that "last request" over some small period (1 second), to avoid stopping/restarting many many times every 1 second, and if it's changed THEN stop the work and restart.
The reason you don't want to use publish / process as-is is that process always runs on the Swing Event Dispatch Thread - not at all suitable for long running calculations.
The key here is that you want to be able to cancel an ongoing computation. The computation must frequently check a condition to see if it needs to abort.
volatile Param newParam;
Result compute(Param param)
{
loop
compute a small sub problem
if(newParam!=null) // abort
return null;
return result
}
To handover param from event thread to compute thread
synchronized void put(Param param) // invoked by event thread
newParam = param;
notify();
synchronized Param take()
while(newParam==null)
wait();
Param param = newParam;
newParam=null;
return param;
And the compute thread does
public void run()
while(true)
Param param = take();
Result result = compute(param);
if(result!=null)
paint result in event thread

Categories