Reputation: 4513
I'm using Runnable as a loop in Android. As this:
Timer timer = new Timer();
timer.schedule(new looper(m_mainView, this),0, Rate);
Which runs every 'Rate' milliseconds.
The looper is as this:
class looper extends TimerTask
{
private ImageView img;
Context c;
public looper(ImageView imgView, Context context)
{
this.img = imgView;
this.c = context;
}
public void run()
{
runOnUiThread(new Runnable() {
@Override
public void run() {
....
I would like to lock the code inside run()
until it is finished, so that if it is called before finished - the thread that calls will return and finish.
I've tried a synchronized(Object)
approach inside run()
which didn't work. Also tried a Mutex, which also didn't work.
Help :)
Upvotes: 0
Views: 2109
Reputation: 9816
First of all, why is there any risk that the run method will be called again? If that's true it sounds like a design deficiency to me. Second, instead of TimerTask, you might be better off using a ScheduledExecutorService instead. That's the standard, simplest and safest way of executing scheduled tasks at a fixed interval. Your user code won't be accessible from anything but the executor service and you can get a ScheduledFuture from it to get a return value so that you know when the task is done (the ScheduledFuture blocks when you call get()). Take a look at Java Concurrency in Practice for more...
Upvotes: 0
Reputation: 65811
The looper
object is solely owned by the timer.schedule
so no-one can call that object's run
method except the timer.schedule
. If the run
method takes longer that the period you have specified then it is likely that the run method will be called again before it completes - especially since you have passed off the actual running of the the task to the UI thread.
You have two simple alternatives:
run
method indicating that you are running and make run
do nothing if it is set.For 1:
class Looper extends TimerTask {
// ** Add this **
volatile boolean running = false;
public Looper() {
}
@Override
public void run() {
// ** Add this **
if (!running) {
running = true;
try {
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
// ** Add this **
} finally {
running = false;
}
}
}
}
Second method:
timer.schedule(new looper(m_mainView, this, Rate),new Date());
...
class Looper extends TimerTask {
final long rate;
final Looper looper;
public Looper(long rate) {
this.rate = rate;
looper = this;
// ...
}
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
// ...
new Timer().schedule(looper, new Date(new Date().getTime() + rate));
}
});
}
}
Upvotes: 1
Reputation: 1914
You should add synchronized
to the method declaration like this:
public synchronized void run()
Upvotes: 0