Android java.util.Timer with reset option - java

I have a scenario where I need to run a certain task at specific interval, however, I want to be able to reset/restart the timer without reinstantiating. Here's my code for better understanding.
private TimerTask beatTask = new TimerTask() {
#Override
public void run() {
beatDetected();
}
};
public void beatDetected() {
timeoutTimer.cancel();
// handle my stuff and restart the timer.
timeoutTimer.schedule(beatTask, 2000);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
(timeoutTimer = new Timer()).schedule(beatTask, 2000);
return Service.START_STICKY;
}
The idea behind this implementation is that beatDetected() can be called from outside event, in which case the next timer tick should happen from that moment on i.e. the elapsed time for the next task should be reset. However, I only get the first tick, and from that point on, the timer just doesn't work.
I'm not limited to using Timer class, anything that will solve the above scenario will work. I was thinging about using postDelayed, but this code is located in a Service, and I don't really need UI thread aware updates.

Using separate thread for timer is considered a somewhat bad practice on Android devices. That's because you are going to waste resources in most scenarios.
If you don't need super precise timing events, you should go with Handler based timers. An example of such timer can be seen here: Repeat a task with a time delay?. This approach works both for Activities and Services.
Also keep in mind that both Handler and Timer based timers will be paused if device goes to sleep mode. If this is not what you need, then use AlarmManager (but keep in mind that using AlarmManager incorrectly may lead to very bad battery performance).
Reseting the Handler based timer:
void resetRepeatingTask() {
mHandler.removeCallbacks(mBeatDetector);
mHandler.postDelayed(mBeatDetector, mInterval);
}

The accepted answer does not work (at least not for me).
A simple solution uses a Timer to trigger a TimerTask, which can easily be reset.
Log.d(TAG, "Restarting timer");
if (timer != null) {
timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Log.d(TAG, "Run the task");
}
}, 1000);
Note that a new TimerTask must be created every time you reset the timer - you can't reuse the old one. If you want to preserve state you will need to get the timer task to run a separate task.

Related

Periodic timertask executed several times at once after Android returns from sleep

I've implemented a background service to update data in my app periodically.
The mechanism works well if my android device is turned on but causing issues when Android is in sleep mode:
Let's imagine the service is running every 15 minutes, then Android goes to sleep for 1 hour and when weaking up again, the service will be executed 4 times at once.
The prefered bahaviour would be running the service once only, in case it missed 1 or more cycles due to sleep.
To run my code periodically, I'm using TimerTask:
public class updateService extends IntentService {
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
if(mTimer != null) {
mTimer.cancel();
}
mTimer = new Timer();
int timer = getPreference("refresh_interval") * 1000;
mTimer.scheduleAtFixedRate(new updateTask (), timer, timer);
return super.onStartCommand(intent, flags, startId);
}
class updateTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// Do job
}
});
}
}
}
I'd appreciate any suggestions how to do better. Thanks!
You are using Timer.scheduleAtFixedRate(TimerTask task, long delay, long period) which explains in its documentation:
If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up."
It seems you want to use Timer.schedule(TimerTask task, long delay, long period) instead, which says:
If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well.
If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well. He is right

How to check continuously which app is opened in foreground from my app's foreground service?

I want to make a app which starts a foreground service to check which are other app are running at any time.
started services and running some logic part in different thread. Created notification and a timer (loop ) which check running apps at every 100 millisecond.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
new Thread() {
public void run() {
startInForeground();
}
}.start();
return START_STICKY;
}
private void startInForeground() {
createNotification();
startTimer();
}
startTimer() function is below, which is checking any app is running in background. Everything is fine, i am able to detect which app is running.
public void startTimer() {
ScheduledExecutorService scheduler = Executors
.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
checkAnyAppOpen();
}
}, 0, 100, TimeUnit.MILLISECONDS);
}
My concern is- I have to run checkAnyAppOpen() function again and again for infinite period of time. So is it good ? or is there any other way to handle it.
What is impact of this method?.
My second question is- I am able to stop my service but still timer(scheduler) is running continuously. How can i stop it ?. How can it affect if it not stopped as i have to again restart my service after some period of time which may run 5 hour to 24 hour. I have to again do stop and restart.
Thanks
I believe for your use-case it is applicable. Just make sure there are no leaks and the service is closed properly.
Use scheduler.shutdown() to stop executor.

Android Java Timer()

I'm using Timer() due to its accuracy but works in the same was as PostDelayed Handler. It's called only once. Here is the Timer code:
public void setWFT() {
WFT = new Timer();
WFT.schedule(new TimerTask() {
#Override
public void run() {
WFTTimerMethod();
}
}, 60000); // 60 seconds delay
}
private void WFTTimerMethod() {
this.runOnUiThread(Timer_Tick);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
// My commands here
}
};
This only calls run() once after 60 seconds once the Timer is started. Sometimes, I have to cancel the Timer to Update the delay (replace the "60000" value). To start the Timer again, I simply recreate the Timer by calling WFT() again with the new delay value.
Problem is, when I cancel the timer using:
WFT.cancel();
WFT.purge();
The Timer does not start. the run() doesn't execute when it's supposed to. So my question is do I use cancel() and purge() or just cancel()?
Thanks
From the Java API on purge():
Most programs will have no need to call this method. It is designed for use by the rare application that cancels a large number of tasks. Calling this method trades time for space: the runtime of the method may be proportional to n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks.
So you only need to call cancel()
from cancel() documentation :
No more tasks may be scheduled on this Timer.

Implementing a timer in java

My situation is, I have two concurrent threads, one that cant start a timer and the other can stop the timer. The timer works in a way such that, once it has started it will count to 5 seconds and execute a function after, it will keep doing this until the timer is stopped by the other thread. How can this be implemented in Java. This is what I have, I feel it is the wrong way of doing it:
Note that sleep is a global volatile variable that the other two threads turn on and off.
void creatTime(final EventHandler handler)
{
Thread timer = new Thread()
{
public void run()
{
try
{
while(true)
{
while(sleep) Thread.sleep(1000);
//invoke function
}
}
catch(IOException e)
{
System.out.println(e);
}
}
};
timer.start();
}
}
You can create a TimerTask and schedule it to run every 5 seconds
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
//Invoke your function here
}
};
//Create a Timer and schedule it
Timer timer = new Timer();
timer.scheduleAtFixedRate(timerTask, 0, 5*1000);
//To terminate the Timer you can call its cancel method.
I agree with the TimerTask recommendation. In general, the more of your thread-related work you can pass on to the higher level features of java.util.concurrent etc. the better. For example, the original code does not deal with early wake-ups from sleep.
In addition, if the sleep variable remains after redesign, it needs to be marked volatile or accessed through synchronized get and set methods. There is a limited set of activities that ensure that writes done in one thread must become visible to reads done in another thread.

java.util.Timer

if(e.getSource()==continuous)
{
TimerTask task = new TimerTask()
{
public void run()
{
rollthedice();
}
};
timer.schedule(task, java.util.Calendar.getInstance().getTime(), 500);
}
if(e.getSource()==stop)
{
timer.cancel();
}
i hit the continuous button, rollthedice() executes looping twice a second, i hit the stop button rollthedice() stops, what i been looking for is a way to hit the continuous button again after i hit stop to start looping the rollthedice() method again, the stop is to stop the continuous cycle of rollthedice() but i want to be able to hit the continuous button again, idk how to do it, i been looking and looking
Updated thoughts:
Runnable runner = new Runnable(){
public void run()
{
rollthedice();
}
}
if(e.getSource()==continuous)
{
future = scheduler.scheduleAtFixedRate(runner, 0, 500, TimeUnit.MILLISECONDS);
}
if(e.getSource()==stop)
{
future .cancel();
}
From the javadoc for Timer.cancel():
Terminates this timer, discarding any currently scheduled tasks. Does not interfere with a currently executing task (if it exists). Once a timer has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it.
This means a new instance of Timer will be required to execute rollthedice() method again.
You could use ScheduledThreadPoolExecutor.scheduleAtFixedRate instead. This will allow you to submit a task, cancel it and then submit again.

Categories

Resources