I have following task: to make service which executes and gets data from Internet every 10 minutes. I try to use combination Service + Timer, but in this case I can't control service (I executes TimerTask with delay in onCreate() method of service, and when I interrupt service TimerTask won't stopped). I need 2 buttons only: "start service" and "stop service". What is the best way in this case? Thank you for helping.
You should use the AlarmManager. See this question Android: How to use AlarmManager for help on that. There is no need to waste a users memory by keeping your service alive doing nothing for 10 minutes. Also, if the phone is asleep, your timer will not run. By using the AlarmManager, the phone will automatically be woken up every 10 minutes and your service can be called to perform its internet download task.
If I understand you well, you want to know how to stop a TimerTask when you interrupt your Service?!
If so, read on, otherwise please explain better.
To stop a TimerTask from executing again (assuming it was scheduled to run repeatedly) you must call the cancel() method. The preferred method is to let the TimerTask itself call the cancel() method after checking some boolean flag which can be set externally.
For example:
class MyTimerTask extends TimerTask() {
private boolean alive = true;
public void run() {
if (alive) {
// do something
} else {
cancel();
}
}
public void stop() {
alive = false;
}
}
Then, it's pretty obvious that when you interrupt your service, you just have to call MyTimerTask.stop().
Related
To give some details about what I'm trying to do: I'm making a Minecraft plugin in Java. I have an Object which is bound to the Player object of Minecraft using a HashMap.
I have a method in this object which is something like:
public void faint() {
... //Apply the effect on the player
//wait for x seconds, and if the player didn't already wake up, wake them up. (player.wakeUp())
}
Obviously, there will be a lot of stuff going on, so I want this to happen asynchronously. The timer will go on in the background and it won't block anything else in the code.
Sorry if my question is too simple, but I really checked the web and I'm new to Java, so forgive my ignorance.
You can create a separate thread by implementing a Runnable interface like this and do the delay in there.
// This is happening in the main thread
Thread thread = new Thread(){
public void run(){
// This code will run async after you execute
// thead.start() below
Thread.sleep(1000)
System.out.println("Time to wake up");
}
}
thread.start();
Use the Bukkit scheduler.
Bukkit.getScheduler().runTaskLater(yourPluginInstance, () -> {
// put code here to run after the delay
}, delayInTicks);
When the code runs after the delay it will run on the main server thread.
I have a process that I want to be triggered by different sources.
Let's say we have one case where we habe some other process (let's call it "manualStarter") under certain conditions wants to trigger this main process. The main process takes a while to complete, let's say 10 seconds to 10 minutes. In case the process is already in progress while the manualStarter is trying to start it, it should not be queued more than once. The second process to trigger the start of the main process could be a "timedStarter" which would trigger the process once in a while, but only if the process is not running, else it would not queue the process to be triggered, instead would try it again some time later.
Now I've tried implementing this kind of process manager by using the isAlive() and join(), but it seems isAlive() is not reliable at all, until it changes its state to alive, 100 threads of this thread might get started (and do sometimes). So seems I couldn't rely on that.
Then I tried using the SingleThreadExecutor service which is closer to what I'm looking for, it's not blocking anything and it only allows a single thread to execute the process, so that's good, however I still don't know how to check the status/lock it properly, or how else I can ensure that the queue for starting the thread doesn't become larger than 1. I read a bit that semaphores are often used for similar kinds of tasks, but I am not sure how I could use them in this scenario.
So how could I achieve what I want? Do I need to implement my own ThreadPoolExecutor? How can I do it? Is there any better way?
Just use a shared flag so the manual starter knows if the thread is running. For example:
// Schedule this to run periodically via ScheduledExecutorService
class ManualStarter {
private final AtomicBoolen isRunning = new AtomicBoolean(false);
private ExecutorService exec = Executors.newSingleThreadedExecutor();
public void run() {
if (!isRunning.getAndSet(true)) {
// It wasn't running so this will start it
exec.submit(new MainProcess(isRunning));
}
}
}
class MainProcess extends Runnable {
private final AtomicBoolean isRunning;
MainProcess(AtomicBoolean isRunning) { this.isRunning = isRunning; }
#Override
public void run() {
// do whatever it does
isRunning.set(false);
}
}
Then somewhere you schedule the main thing to run periodically doing something like:
ScheduledExectorService sched = Executors.newScheduledThreadPool(1);
ManualStarter starter = new ManualStarter();
// Every 10 seconds will check if MainProcess is running and will start
// it if it's not
sched..scheduleAtFixedRate(starter, 0, 10, SECONDS);
You should rather use ExecutorService for that. There is couple of implementations available (including ScheduledExecutorService that allows you to schedule deffered and/or repeating tasks - check Executors). Just pick one that fits your needst the best.
As for conditional execution the task is simple. Define some sort of accessible flag that holds the current "state" of given task. If it is running - do nothing, if it is not running - schedule execution.
Simple example:
//our flag
private volatile AtomicBoolean isRunning=new AtomicBoolean(false);
public void scheduleTask(){
if(isRunning.get()){
return; // do nothing
}else{
synchronized(isRunning){
if(isRunning.get()){
return;
}else{
isRunning.set(true)
scheduleNewTask();
}
}
}
}
For any how-tos check the official Oracle's documentaion about Executors.
I have use AtomicBoolean in this example to mock "mutable" boolean. This can be done with boolean as well but synchronization needs to be done on different object (eg. dedicated private Object lock=new Object();)
I've a runnable instance that self-schedules itself again at the end of its run method:
private class MyRunnable implements Runnable {
private volatile boolean cancelled = false;
private Handler handler;
public MyRunnable(Handler h){
handler = h;
}
#Override
public void run(){
//Do stuff
if(!cancelled){
//Preemtion possible here?
handler.postDelayed(this, 1000);
}
}
public void selfStart(){
cancelled = false;
handler.removeCallbacks(this);
handler.post(this);
}
public void selfCancel(){
cancelled = true;
handler.removeCallbacks(this);
}
}
The runnable is first scheduled in the main thread calling selfStart from an activity's onStart.
At the same time, the runnable can be externally cancelled (calling selfCancel) from the activity's onStop and also from a Broadcast Receiver.
AFAIK Runnable.run, Activity.onStop and BroadcastReceiver.onReceive run in the same thread (the main one), so at first glance I thought there would be no thread-safety issues.
But it looks like sometimes, the runnable is being preemted in the middle of its run call, then it is cancelled from the activity or receiver, and then it resumes and re-schedules itself again.
Is this possible?
UPDATE:
I'll try to explain better the issue. The class shown above is intended to run tasks periodically in the main thread. In the "do stuff" comment there's actually code that updates a TextView with a value passed to the MyRunnable constructor. The activity cancels the current runnable and starts a new one when certain intents are received. Despite the current runnable is always requested to cancel itself before the new one is created, sometimes it is being left running along with the new one, so the text view is showing alternating values. This is not the intended behavior.
I thought if the runnable was currently running in the main thread, it would run until completion, and then other runnables or event handlers would be taken out of the queue and executed if needed, but no pending event or runnable could be "half executed".
There are two kinds of tasks running in the main thread that are related to the problem:
R1: The MyRunnable self-scheduling task. Runs and then it self-posts itself again with a delay of 1s.
R2: The event handlers that request cancellation of the current MyRunnable instance and create a new R1'. These happen randomly and are executed only once.
I've contemplated two scenarios. The first one:
R1 is already running in the main thread.
R2 arrives and is enqueued in the main thread.
R1 finishes running and posts itself again.
R2 runs and removes callbacks for R1.
R1 should never run again.
And the second one:
R1 is not running but is scheduled.
R2 arrives and removes callbacks for R1.
R1 should never run again.
Theoretically, if there's no preemtion, and there's only a single thread, how comes sometimes there are two R1s in the main thread?
As you have no synchronization on selfStart or selfCancel this is entirely possible.
An unreleated note, selfCancel could be called on a separate thread after your if statement in your run method has checked the value of cancelled. MyRunnable would then get one more call to run, which would end immediately as it's been cancelled.
My suggestion would be to move the //Do stuff inside the canceled check.
This avoids the race regardless of assumptions about which thread things are running on.
#Override
public void run(){
if(!cancelled){
//Do stuff
handler.post(this);
}
}
In general for maintainability, try to write code that works correctly regardless of the thread it is being run on. You never know when somebody will call selfCancel() on some other thread later thinking it is okay, when you have assumed they won't do that.
Well as others have said, there's no way a runnable can be preempted in a single thread. I also thought this idea was absurd. Shame on me for coming up with that nonsense.
There was nothing wrong with the runnables themselves. They were launched in the activity's onStart, and cancelled from Intents received by the activity, or in the activity's onStop. An this is the root of the problem: assuming onStart and onStop would run in a predictable order. Sometimes when coming back to the activity, a second onStart was executed before the first activity's onStop. Two tasks were running and the thing messed up to a point where the first task was never terminated.
Ensuring no task is launched without previous termination of the current one solved the issue.
Globally, I have a the following:
Timer timer = new Timer();
in my onResume() I have the following code.
timer.schedule(new syncTimerTask(), 1, 30000);
and my syncTimerTask is as follows :
class syncOutgoingUpdatesTimerTask extends TimerTask
{
public void run()
{
//some sync process with outer back end server
//fetch results etc
myHandler.post(myRunnable);
}
}
my handler and runnable are declared globally as follows
final Handler myHandler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
//update GUI, text views whatever.
}
};
And inside my onPause() I call timer.cancel();
The above code is neat, straight to the point and does the job perfectly.
But in order to grasp the idea better, I have some concerns and questions.
Assume the syncing too a lot of time, and the user pressed the back button. This will cause the onPause to get caused , which will stop the timer from repeating itself, however the running TimerTask will continue running. But what happens when the code reaches the line of myHandler.post(myRunnable); where the handler calls the runnable, but there is no GUI to update ? Do I get a null pointer there ?
Assume the sync started and again it took a lot of time, in which state, the user pressed the home button and got out of the app and removed the app from the 'recent apps' which 'kills' the app, calling onDestroy() on all methods. In this case, does the thread of the timer (which is a seperate thread and not the UI thread, stops wherever it is, (even though it might be in the middle) because it is associated with the app ?), assume this is true, the code won't even reach the myHandler.post(myRunnable); so no null pointers will occur.. is this the case ?
Yes, the event will run, and if you nullify things out it might cause problems. The best you can do is to have a flag that tells you, from your Runnable, that the activity is paused.
No, the app is not killed, just stopped (unless the Android process manager kills it for memory as usual). In this case your timer thread continues running and executes the Runnable in the main thread, with the same potential problems of 1.
I tried everything. This one too How to stop the task scheduled in Java.util.Timer class
I have one task that implements java.util.TimerTask
I call that task in 2 ways:
I schedule Timer like this:
timer.schedule(timerTask, 60 * 1000);
sometimes I need that work to start immediately and it has to cancel timerTask if there is any that is working
cancelCurrentWork();
timer.schedule(timerTask, 0);
This implementation doesn't stop current work:
(documentation says: If the task is running when this call occurs, the task will run to completion, but will never run again)
But I need it to stop.
public static void cancelCurrentwork() {
if (timerTask!= null) {
timerTask.cancel();
}
}
This implementation just cancels the timer but leaves currently doing task to be finished.
public static void cancelCurrentwork() {
if (timer!= null) {
timer.cancel();
}
}
Is there a way in timer to STOP current executing taks, something like Thread.kill() or something? When I need that task to stop I want it to loose all its data.
There is no way for the Timer to stop the task in its tracks.
You will need to have a separate mechanism in the running task itself, that checks if it should keep running. You could for instance have an AtomicBoolean keepRunning variable which you set to false when you want the task to terminate.
if your timer is using some sort of file/socket etc, you can close that object from outside the timer, and the timer task will throw an exception, and you can use it to stop the timer.
but in general you need some sort of poison pill to successfully stop a separate thread/timer.