I'm designing an app that has a recurring task of sending presence to a dedicated server as long as the app is in foreground.
In my searches across the web I saw a few different approaches and wanted to know what is the best way of doing this.
What is the best way to schedule a server call?
The options I saw were:
Timer .
ScheduledThreadPoolExecutor.
Service.
BroadcastReciever with AlarmManager.
What's your opinion?
EDIT: The reason I need this is for a chat based app that sends all the user actions to a remote server. i.e. user is typing a message, user is reading a message, user is online, user is offline etc.
This means that once every interval, I need to send the server what I'm doing, since I open a chat room with other people, they need to know what I'm doing.
Similar to the whatsapp message feedback mechanism:
EDIT #2:
Recurring tasks should now be scheduled almost always via the JobScheduler API (or FirebaseJobDispatcher for lower APIs) in order to prevent battery draining issues as can be read in the vitals section of the Android training
EDIT #3:
FirebaseJobDispatcher has been deprecated and replaced by Workmanager, which also incorporates features of JobScheduler.
I am not sure but as per my knowledge I share my views. I always accept best answer if I am wrong .
Alarm Manager
The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes. If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched. To prevent this, your BroadcastReceiver and Service will need to implement a separate wake lock policy to ensure that the phone continues running until the service becomes available.
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Timer
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
synchronized public void run() {
\\ here your todo;
}
}, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1));
Timer has some drawbacks that are solved by ScheduledThreadPoolExecutor. So it's not the best choice
ScheduledThreadPoolExecutor.
You can use java.util.Timer or ScheduledThreadPoolExecutor (preferred) to schedule an action to occur at regular intervals on a background thread.
Here is a sample using the latter:
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate
(new Runnable() {
public void run() {
// call service
}
}, 0, 10, TimeUnit.MINUTES);
So I preferred ScheduledExecutorService
But Also think about that if the updates will occur while your application is running, you can use a Timer, as suggested in other answers, or the newer ScheduledThreadPoolExecutor.
If your application will update even when it is not running, you should go with the AlarmManager.
The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running.
Take note that if you plan on updating when your application is turned off, once every ten minutes is quite frequent, and thus possibly a bit too power consuming.
Timer
As mentioned on the javadocs you are better off using a ScheduledThreadPoolExecutor.
ScheduledThreadPoolExecutor
Use this class when your use case requires multiple worker threads and the sleep interval is small. How small ? Well, I'd say about 15 minutes. The AlarmManager starts schedule intervals at this time and it seems to suggest that for smaller sleep intervals this class can be used. I do not have data to back the last statement. It is a hunch.
Service
Your service can be closed any time by the VM. Do not use services for recurring tasks. A recurring task can start a service, which is another matter entirely.
BroadcastReciever with AlarmManager
For longer sleep intervals (>15 minutes), this is the way to go. AlarmManager already has constants ( AlarmManager.INTERVAL_DAY ) suggesting that it can trigger tasks several days after it has initially been scheduled. It can also wake up the CPU to run your code.
You should use one of those solutions based on your timing and worker thread needs.
I realize this is an old question and has been answered but this could help someone.
In your activity
private ScheduledExecutorService scheduleTaskExecutor;
In onCreate
scheduleTaskExecutor = Executors.newScheduledThreadPool(5);
//Schedule a task to run every 5 seconds (or however long you want)
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// Do stuff here!
runOnUiThread(new Runnable() {
#Override
public void run() {
// Do stuff to update UI here!
Toast.makeText(MainActivity.this, "Its been 5 seconds", Toast.LENGTH_SHORT).show();
}
});
}
}, 0, 5, TimeUnit.SECONDS); // or .MINUTES, .HOURS etc.
Quoting the Scheduling Repeating Alarms - Understand the Trade-offs docs:
A common scenario for triggering an operation outside the lifetime of your app is syncing data with a server. This is a case where you might be tempted to use a repeating alarm. But if you own the server that is hosting your app's data, using Google Cloud Messaging (GCM) in conjunction with sync adapter is a better solution than AlarmManager. A sync adapter gives you all the same scheduling options as AlarmManager, but it offers you significantly more flexibility.
So, based on this, the best way to schedule a server call is using Google Cloud Messaging (GCM) in conjunction with sync adapter.
I have created on time task in which the task which user wants to repeat, add in the Custom TimeTask run() method. it is successfully reoccurring.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;
import android.content.Intent;
public class MainActivity extends Activity {
CheckBox optSingleShot;
Button btnStart, btnCancel;
TextView textCounter;
Timer timer;
MyTimerTask myTimerTask;
int tobeShown = 0 ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
optSingleShot = (CheckBox)findViewById(R.id.singleshot);
btnStart = (Button)findViewById(R.id.start);
btnCancel = (Button)findViewById(R.id.cancel);
textCounter = (TextView)findViewById(R.id.counter);
tobeShown = 1;
if(timer != null){
timer.cancel();
}
//re-schedule timer here
//otherwise, IllegalStateException of
//"TimerTask is scheduled already"
//will be thrown
timer = new Timer();
myTimerTask = new MyTimerTask();
if(optSingleShot.isChecked()){
//singleshot delay 1000 ms
timer.schedule(myTimerTask, 1000);
}else{
//delay 1000ms, repeat in 5000ms
timer.schedule(myTimerTask, 1000, 1000);
}
btnStart.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
Intent i = new Intent(MainActivity.this, ActivityB.class);
startActivity(i);
/*if(timer != null){
timer.cancel();
}
//re-schedule timer here
//otherwise, IllegalStateException of
//"TimerTask is scheduled already"
//will be thrown
timer = new Timer();
myTimerTask = new MyTimerTask();
if(optSingleShot.isChecked()){
//singleshot delay 1000 ms
timer.schedule(myTimerTask, 1000);
}else{
//delay 1000ms, repeat in 5000ms
timer.schedule(myTimerTask, 1000, 1000);
}*/
}});
btnCancel.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
if (timer!=null){
timer.cancel();
timer = null;
}
}
});
}
#Override
protected void onResume() {
super.onResume();
if(timer != null){
timer.cancel();
}
//re-schedule timer here
//otherwise, IllegalStateException of
//"TimerTask is scheduled already"
//will be thrown
timer = new Timer();
myTimerTask = new MyTimerTask();
if(optSingleShot.isChecked()){
//singleshot delay 1000 ms
timer.schedule(myTimerTask, 1000);
}else{
//delay 1000ms, repeat in 5000ms
timer.schedule(myTimerTask, 1000, 1000);
}
}
#Override
protected void onPause() {
super.onPause();
if (timer!=null){
timer.cancel();
timer = null;
}
}
#Override
protected void onStop() {
super.onStop();
if (timer!=null){
timer.cancel();
timer = null;
}
}
class MyTimerTask extends TimerTask {
#Override
public void run() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
final String strDate = simpleDateFormat.format(calendar.getTime());
runOnUiThread(new Runnable(){
#Override
public void run() {
textCounter.setText(strDate);
}});
}
}
}
I am using timer task to execute asynctask at fixed interval of time the time five minutes. but timer task sometimes started to misbehave like it doesn't get
at fixed delay in fact it get executed after 10 minutes twice instead of getting every 5 minute why so?
Here is my code
Timer timer = new Timer();
mytimer Mytimer = new mytimer();
timer.scheduleAtFixedRate(Mytimer, 300000, 300000);
class Mytimer extends TimerTask {
#Override
public void run() {
// TODO Auto-generated method stub
new DetailPosition().execute();
}
}
So help me in this
If the timer task is scheduled on a thread pool where all the threads are in use, then it will have to wait for one to become available before running your task.
Consider the following -
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(() -> {Thread.sleep(500); System.out.println(new Date());}, 0, 200, TimeUnit.MILLISECONDS);
Here the task takes longer than the interval, so the tasks will just queue up until you run out of memory.
Since i have started using two timer task on same service it started misbehaving.
As i am calling api in both timer task 1 is calling api after 30 seconds and another timertask is calling and api after 5 minutes. now they are misbehaving in the way that some times timer task which call api after 5 minutes started calling an api at any timer instead of after 5 minutes. Some times it hits an api 10-15 times between 5 minutes and some timer it hits an api once in after 20-25 minutes.
Here is my code of timer task
Timer timer, timer_update_current_position;
if (timer == null) {
timer = new Timer();
mytimer Mytimer = new mytimer();
timer.scheduleAtFixedRate(Mytimer, 300000, 300000);
}
if (timer_update_current_position == null) {
timer_update_current_position = new Timer();
TimerCurrentPos timerCurrentPos = new TimerCurrentPos();
timer_update_current_position.scheduleAtFixedRate(timerCurrentPos,
30000, 30000);
}
Please help me how to resolve this issue because its adding data in bult on my server.
I recently just learned and developed a widget. I understand that the widget have an auto update at every 30 - 60 minutes minimum. Now I have been asked to reduced that auto update to 5 minutes.
So I have thought up for creating another Service Thread that is constantly running a countdown timer every 5 minutes and refreshes the app to check for any possible errors. These errors are actually ping tests results. If a server is down, I will execute a Toast Message to inform the user that this server is down.
So, how should I go about doing this? Or is there a better suggestion. Please enlighten me.
May this helps you:
Buddy use TimerTask to call after specific time interval
Timer timer = new Timer();
timer.schedule(new UpdateTimeTask(),1, TimeInterval);
and
class UpdateTimeTask extends TimerTask {
public void run()
{
// code here
}
}
Or You can Use AlaramManager also:
Set AlarmManager like this:
private static final int REPEAT_TIME_IN_SECONDS = 60; //repeat every 60 seconds
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),
REPEAT_TIME_IN_SECONDS * 1000, pendingIntent);
Change AlarmManager.RTC to AlarmManager.RTC_WAKEUP if u want to wake up phone when it goes off. More about AlarmManager Click Here
Those two parameters also means that your alarm time will be System.currentTimeMilis() which is time in UTC.
I think better use runnable with postDelayed, like this:
private Handler handler = new Handler();
private Runnable runnable = new CustomRunnable();
private class CustomRunnable implements Runnable {
public void run() {
// your logic
handler.postDelayed(runnable, REFRESH_TIME);
}
}
REFRESH_TIME — your constant to refresh in millis. Just run once handler.postDelayed(runnable, REFRESH_TIME); where you want.
I need to run a periodic task in an Android application. I currently use a timer like this:
final Handler guiHandler = new Handler();
// the task to run
final Runnable myRunnable = new Runnable() {
#Override
public void run() {
doMyStuff();
}
};
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
guiHandler.post(myRunnable);
}
}, 0, 30000); // run every 30 seconds
This does exactly what I need, but there is a problem: if I change the time on the emulator or phone, the timer stops running. This is what appears in the log when I change the time:
D/SystemClock( 331): Setting time of day to sec=1278920137
W/SystemClock( 331): Unable to set rtc to 1278920137: Invalid argument
Nothing about the timer being interrupted, but it clearly doesn't run anymore after the system clock has changed. I need the task to keep running all the time as long as the application is running.
How can I restart the timer if it gets stopped like this? There's no method on the Timer or TimerTask to check whether it's currently running, so I can't know when to reschedule it. Any ideas?
I think there are a few ways to do this. I wouldn't use the timer in either case.
You can use a handler to run your task in a postDelayed call. Your task would then have to re-register itself with the handler from within itself.
final int ONE_SECOND = 1000; // one second
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
... // do some stuff
if (expression) {
handler.postDelayed(this, ONE_SECOND);
}
}
}, ONE_SECOND);
This will keep the task running while your app is alive. You can also adjust the delayed rate in the postDelayed within the Runnable. This way is semi predictable as long as you make another Looper. Using the main thread may or may not be appropriate depending on what the task is.
There is also an AlarmManager, that you can gain access to via the Context interface, which is meant for recurring tasks tasks at more precise intervals. It's a little more complex to use but you get the flexibility of having use of the RTC and persisted repeatable tasks.
AlarmManager manager = mContext.getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC,
<start_time_millis>,
<period_millis>,
pendingIntent);
For example, the pending intent can fire a broadcast intent that you can listen to elsewhere. You can create this pendingintent in the onCreate of your custom Application object and cancel the intent in the onTerminate().