Troubles with Timer - android - java

i have a problem with a method that i want to be called every x seconds.
In the constructor of my class I have something like that :
public class MyClass extends RelativeLayout{
public MyClass(Context context) {
// bla bla….
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
callMyMethodPeriodically();
}
}, 0, 20000); // every 20 seconds..
}
}
When I press the back button, the callMyMethodPeriodically method still is being called..
Even if i exit the application!
Do you have any ideas?? How can i stop this periodically calling?
Thank you

Try to override the onPause method on your Activity, the onPause will be called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.
#Override
protected void onPause() {
super.onPause();
mTimer.cancel();
mTimer.purge();
mTimer = null;
}

You can try timer.canel() method or you can do it by this way
private Runnable runnable = new Runnable()
{
public void run()
{
//
// Do the stuff
//
handler.postDelayed(this, 1000);
}
};
and to stop:
handler.removeCallbacks(runnable);
or this way
you could look into using a ScheduledThreadPoolExecutor instead of a Timer.
Usage is pretty straight forward. You create an instance of an executor:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( 1 );
And then when you want to add a task you call:
executor.scheduleAtFixedRate( myRunnable, delay, interval, unit );
Where myRunnable is your task (which implements the Runnable-interface), delay is how long before the task should be executed the first time, interval is time between the execution of the task after first execution. delay and interval are meassured based on the unit parameter, which can be TimeUnit.* (where * is SECONDS, MINUTES, MILLISECONDS etc.).
Then to stop the execution you call:
executor.shutdownNow();

Related

Delay execution of code in method Java

I want to generate random number after every 2 seconds in my java (Android) program continuously for at least 10 minutes. But I just want to pause/delay execution of code in only one method and not the whole program.
I tried using Thread like this -
boolean stop = false;
int random_number = 0;
while(true){
if(stop){ //if stop becomes true, then
return; //terminate the method
}
random_number = Math.random(); //generate random number
//which is used bu some other
//part of code
try {
Thread.sleep(2000); //delay the code for 2 secs
} catch(InterruptedException ex) { //and handle the exceptions
Thread.currentThread().interrupt();
}
}
However, this doesn't work as Thread.sleep stop the whole program execution instead on just stopping execution of code inside method and my whole screen becomes blank.
I also tried using Handler but it didn't work either as it doesn't stop execution of code in my method and instead just stack up.
This will demonstrate the working of it better -
while(true){
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs"); //this gets printed
//later
}
}, 2000);
System.out.println("Before 2 secs"); //this gets printed first
}
So the code stacks up making it equivalent to using while loop and make it incredibly slow.
Also, since I'm developing app for Android, I'm running on Java SE 6, so I can't use scheduleAtFixedRate. Is there any other way in which I can accomplish this?
Thanks a lot!
private Timer timer;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Generate number
}
}, 2000, 2000);
//Documentation (From SDK)
/**
* Schedule a task for repeated fixed-rate execution after a specific delay
* has passed.
*
* #param task
* the task to schedule.
* #param delay
* amount of time in milliseconds before first execution.
* #param period
* amount of time in milliseconds between subsequent executions.
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0 || period <= 0) {
throw new IllegalArgumentException();
}
scheduleImpl(task, delay, period, true);
}
and when you want to stop it
timer.cancel()
Option 1: Using threads, you might run your job off the main (UI) thread:
new Thread(new Runnable() {
// some code here ...
// This might be in a loop.
try {
Thread.sleep(2000);
} catch(InterruptedException ex) {
// Handle ...
}
}
}).start();
Then, if this new thread you'd like to modify UI (i.e. show/hide button, display something on the screen etc), remember to pass that through the UI thread, as only this one can modify the UI. You might consider using Activity.runOnUiThread() for that.
Option 2: Another, more Android-style way of approaching that issue is to use AsyncTask. It contains three callbacks which can be used to do work on- and off- the UI thread. Sketch of such a code could look like:
private class MyTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
// This method is running off the UI thread.
// Safe to stop execution here.
return null;
}
protected void onProgressUpdate(Void... progress) {
// This methid is running on the UI thread.
// Do not stop thread here, but safe to modify the UI.
}
protected void onPostExecute(Long result) {
// Also on UI thread, executed once doInBackground()
// finishes.
}
}
Option 3: Then there is also a Timer, as suggested by #Stultuske. It's less flexible then AsyncTask, but handles the interval for you.
Depending on your needs, you can still accomplish what you seek with Handler.
You don't have to create/start the Handler in a while loop(which, as you noticed, just stacks up unless you stop the loop itself, but it is a nonsense).
Just create the Handler and tell him to post delayed your Runnable instance. In the Runnable at the very end you check your conditions. If it is still OK, then post another runnable delayed, else you do nothing and the Handler will have no more executions.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs");
random_number = Math.random();
if (!stop) // should not be stopped, so we add another runnable;
{
handler.postDelayed(this, 2000);
}
}
handler.postDelayed(runnable, 2000);
The only downside is that Handler could freeze if the device is not used for a while, meaning it will start the counting back from where it left once the device screen is turned on.
It could do like 1 minute of correct work, then block at 1.4 seconds when the device is gone in sleep mode, and once it is turned on again, Handler would do the remaining 0.6 seconds.
Still, not knowing your needs you may be unaffected by this behavior and the answer may fit you.
if you want to use thread, do it like this :
Thread t = new Thread(){
public void run(){
while(true){
if(stop) break;
random_number = Math.random();
sleep(2000);
}
}
};
t.start();

How to cancel a timer.schedule() invocation early

I have scheduled a method to run at a certain date in the future; however, there are certain events that may or may not happen before that date that would mean I want to run the method earlier than the specified date; how can I do this? I currently have:
Timer timer = new Timer();
TimerTask task = new TaskToRunOnExpriation();
timer.schedule(task, myCalendarObject.getTime());
I will have many of these TimerTask's running in my application, stop specific instances of them if a certain even happens?
EDIT
I will only ever want to cancel a single Timer for a given event, is there a way of managing the identities for the Timers such that I can easily find and stop it?
If you have thousands of them you should use a ScheduledExecutorService which will pool threads rather than a Timer which will use one thread per timer.
The ScheduledFutures returned by the executor service when you schedule a task also have a cancel method to cancel the underlying tasks: future.cancel(true);.
As for cancelling the right task, you could store the futures in a Map<String, Future> so you can access them by name or id for example.
In C# I would say use delegates, but that is not an option in Java. I would work off this idea:
class Timers
{
Timer timer1;
Timer timer2;
ArrayList<Timer> timerList;
public Timers()
{
// schedule the timers
}
// cancel timers related to an event
public void eventA()
{
timer1.cancel();
timer2.cancel();
}
public void eventB()
{
for(Timer t : timerList)
t.cancel();
}
}
Use this schedule method.
public void schedule(TimerTask task,Date firstTime,long period)
task--This is the task to be scheduled.
firstTime--This is the first time at which task is to be executed.
period--This is the time in milliseconds between successive task executions
I use Timer in android to update a progress bar.Here is some of my code, hoping it can help you:
Timer timer ;
#Override
protected void onCreate(Bundle savedInstanceState) {
//....
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
updateLogoBarHandler.sendEmptyMessage(0);
Log.e("SplashActivity","updating the logo progress bar...");
}}, 0, 50);
//.....
}
//here do the timer.cancel();
private Handler updateLogoBarHandler = new Handler() {
public void handleMessage(Message msg) {
if(logobarClipe.getLevel() < 10000){
logobarClipe.setLevel(logobarClipe.getLevel() + 50);
}else{
timer.cancel();
}
super.handleMessage(msg);
}
};

Is it really so hard to "postpone" a task (or "wait for idle")

How do I accomplish a "wait for idle" model with the properties:
When a method do() is called, after X delay, a close() method will be called.
If I call the do() method again before X time has passed, the call to close() must be postponed.
EXAMPLE
Scenario 1: (for timeout = 10 secs):
The user calls do() at time 0.
At time 10, the close() method is called because the user has not called do() again.
Scenario 2: (also timeout = 10 secs):
The user calls do() at time 0. (so at 10 the close() method should be called).
At time of 8, the user calls do() again.
At time of 10 nothing happens because the close() was postponed 10 seconds.
At time 18, the close() method is called, because the user has not called do() again since 8.
What i have tried:
private static final long delay = 10000;
private Timer t;
private TimerTask tt;
public void do() {
...
// check old timer first:
if (t != null) t.cancel();
// create new timer
t = new Timer();
tt = new TimerTask() {
#Override
public void run() {
close();
}
}
// run it
t.schedule(tt, System.currentTimeMillis() + delay);
}
private void close() {
// do some cleanup here
}
This code is very ugly.
It's also very unefficient and memory-consuming, because the do() function is getting called about 50 times per second.
What should I do to get this working in an efficient and neat way? (Is it really so hard?)
You are on a right way and it is not a hard one.
Here is what I want to suggest you. Create timer only once. Make it a member of class. Create its instance in constructor.
When method is called create a task as you already do now. You can however create separate class and even create it instance in advance and when do() method is called just schedule it, so the close() will be called according to your schedule.
When do() is called cancel the previously created close task. This will make sure that you will not close anything if method do() was called again.
BTW since do is a reserved word in java you cannot call method this way. This means that your code even cannot be compiled. Change the name.
Set a 10 second timer task when you open()
Keep a variable long lastCall which gets set to System.currentTimeMillis() from doIt()
In the time task body, check whether lastCall is within 10 seconds. If so, reschedule the timer task for the remaining time. If not, call close()
Don't forget to synchronize on something when you read to or write from lastCall
I've found a suitable solution:
public class TimerExample {
private TimerTask tt;
ScheduledFuture<?> future;
private ScheduledThreadPoolExecutor s;
public TimerExample() {
s = new ScheduledThreadPoolExecutor(1);
tt = new TimerTask() {
#Override
public void run() {
close();
}
};
doSomething();
}
public void doSomething() {
if (future != null) future.cancel(true);
future = s.schedule(tt, 3000, TimeUnit.MILLISECONDS);
System.out.println("do");
}
public void close() {
System.out.println("Close");
}
}

Servlet on startup that triggers an event after regular interval of time using timer class?

I have a servlet that starts on start of tomcat. I need a functionality in that servlet that triggers the event after a regular interval of time i.e 1 hour and
runs in the back ground? Here is my code :-
in main method
MyTask contentTask = new MyTask();
long interval = 60 * 60 * 1000;
Timer timer = new Timer();
timer.schedule(contentTask, new Date(), interval);//line 1
System.out.println("line2");//line2
MyTask
public class MyTask extends TimerTask {
#Override
public void run() {
System.out.println("Inside my task");
}
}
i am expecting as soon control comes to line 2 , run method gets executed and then it keeps on execting the task after ever 60 minutes like background thread does. But
control does not come to run method after line 2. I am not sure what i am missing here and why run method is not getting executed?
Edit:- I think problem is with interval value if i make it one minute i.e 1 * 60 * 1000; contol comes to run method . Looks like even the first time task will be executed after specified time interval i.e 60 minutes but i want to execute the task immediately as soon as it executes the line 1 and then repeat it after 60 minutes How to go for this?
May be you should start as daemon. new Timer(true)
It seems to me that you are looking for a ServletContextListener. You can execute code at the deployment before everything else. In this code you use Executors instead of a "Vanilla" Thread, and schedule it.
#WebListener
public class GlobalContext implements ServletContextListener {
private ServletContext app;
private ScheduledExecutorService scheduler;
//What to do when app is deployed
public void contextInitialized(ServletContextEvent event) {
//Init Context
app = event.getServletContext();
//In my case I store my data in the servlet context with setAttribute("myKey", myObject)
//and retrieve it with getAttribute("myKey") in any Servlet
// Scheduler
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new AutomateRefresh(), 0, 60, TimeUnit.MINUTES);
}
//Do not forget to destroyed your thread when app is destroyed
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdown();
}
//Your function
public class AutomateRefresh implements Runnable {
public void run() {
//Do Something
}
}
}
FYI, Executors is part of Java 5 and further.

Is there any possibility to pause&resume a TimerTask in Android?

I'm calling this tasks:
TimerTask taskA = new ThreadA(this);
TimerTask taskB = new ThreadB(this);
tasks.add(taskA);
tasks.add(taskB);
timer.schedule(taskA, 10000);
timer.schedule(taskB, 5000);
And here are the two TimerTasks:
public class ThreadA extends TimerTask {
private Ghost ghost;
public GhostThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.stopBeingDeadAndBeAwesomeAgain();
}
}
public class ThreadB extends TimerTask {
private Ghost ghost;
public WarnThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.beDeadAgain();
}
}
As you can see, I just call a method after 5 resp. 10 seconds. From time to time I would like to pause the "countdown". This means i want that the time until the 5 seconds are passed isn't running anymore. And then in a later point in time, I would like to resume it.
How can I achieve that??
The simplest solution would be to simply make a copy of the TimerTask, cancel it to pause, purge if you want, and then reschedule it to resume.
// pause
long timeLeft = 5000 - (new Date().getTime() - taskB.scheduledExecutionTime());
ThreadB taskBpaused = taskB.clone();
taskB.cancel();
timer.purge();
taskB = taskBpaused;
// resume
timer.schedule(taskB, timeLeft, ...);
Important note: if the task hasn't run yet, then this won't work. Google's documentation states that if it hasn't run, scheduledExecutionTime() will return an undefined value, and I don't have the capability to test what exactly that means at the moment. Needless to say, if you aren't sure it's already run, you'll need some kind of conditional to make sure the value isn't undefined.

Categories