I have a background service to be called everyday at 1pm. At 1 pm, 3 values in my Firebase database should be set to 0. When the user launches a certain activity the background service is triggered. The values reset to 0 at 1pm like i want but, every time after 1pm when the activity is launched by the user the service runs resetting my values. How can I get the values reset to 0 at 1pm and not again until 1pm the next day?
Below is my code within the Service class
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 13);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
timer = new Timer();
timer.schedule(new TimerTask()
{
#Override
public void run()
{
String id = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseDatabase.getInstance().getReference().child("Users").child(id).child("steps").setValue(0);
FirebaseDatabase.getInstance().getReference().child("Users").child(id).child("bonusScore").setValue(0);
FirebaseDatabase.getInstance().getReference().child("Users").child(id).child("stepsScore").setValue(0);
}
}, calendar.getTime(), TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
return START_STICKY;
}
#Override
public void onDestroy()
{
super.onDestroy();
}
This is the Code starting the service. This method is called in the oncreate method of this activity.
private void startBackgroundService()
{
startService(new Intent(this, BackgroundService.class));
}
you can use work manager to schedule a task.here you can find getting started guide......
Related
I have to run a task in background when reach the scheduled time.i assigned the task of waking up my service to Alarm Manager and it does well if the app is background/running.service keep running fine on app's background as well as foreground states if am not changing the state of app after beginning the service.for the purpose of well understanding the scenario's given below.
Case 1:
1.Setting up the schedule and sending the time to alarm manager and keep the app running.
2.Alarm manager calls the service when the time is reaching.
3.Service start running
4.when i close my app service get stopped
Case 2:
1.Setting up the schedule and sending the time to alarm manager and closing the app.now app in background.
2.Alarm manager calls the service when the time is reaching.
3.Service start running
4.Relaunching the app.service continuing running/working fine.
5.Now closing the app and the result is service dead.
I have to call the service only by Alarm Manager , not on every time when app launches for that purpose in service onStartCommand method i returned START_NOT_STICKY and i don't want to use START_STICKY.if i goes to START_STICKY it won't consider the scheduled time.and the thing is i don't want to check the time again as it's doing well by Alarm Manager.
When app running on low memory the services get destroyed.is the solution using startForeground instead of startService ?
How can i make my service running stable without bothering about the app opening/closing states ?
Setting schedule
public void setAction(View v) {
Calendar calendar = Calendar.getInstance();
int hour = Integer.parseInt(HH.getText().toString());
int minute = Integer.parseInt(MM.getText().toString());
int second = Integer.parseInt(SS.getText().toString());
String peried = PP.getText().toString();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.AM_PM, peried.equalsIgnoreCase("AM") ? Calendar.AM : Calendar.PM);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
myIntent.putExtra(ACTION,
ACTION_SC_1);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, REQUEST_CODE_SC_1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
}
Service class
public class MyService extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
final String action = intent.getStringExtra(ACTION);
final Handler handler = new Handler();
final Timer timer = new Timer();
final TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Toast.makeText(MyAlarmService.this, "Running....", Toast.LENGTH_LONG).show();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 1000, 5000); //execute in every 5000 msdo
// this.stopSelf();
} catch (Exception e) {
//TODO
}
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "Killed", Toast.LENGTH_LONG).show();
}
There are many ways to avoid killing of service...but we can not guarantee it. In low memory situations the service will be killed by the os. At this situation if you return START_STICKY this will restart the service with null intent. If you want the intent to be not null return START_REDELIVER_INTENT
See the android docs here
I'm making a simple alarm clock app and now I'm having problem with the service which checks if the current time matches the set time and starts another activity. Here's the code:
#Override
public int onStartCommand(Intent intent, int flags, int startID){
hourSet = intent.getIntExtra("hourSet", 0);
minuteSet = intent.getIntExtra("minuteSet", 0);
checkTime();
return START_STICKY;
}
private void checkTime(){
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
time.setToNow();
currentHour = time.hour;
currentMinute = time.minute;
if(currentHour == hourSet && currentMinute == minuteSet){
Intent i = new Intent(AlarmService.this, AlarmTime.class);
startActivity(i);
cancel();
}
}
}, 0, UPDATE_INTERVAL );
}
I have debugged the service, everything is fine until the if statement. When the current time matches the set time, the app crashes.
So how to fix this ?
Why people dont include catLog?
Problem is you are trying to start activity on service task, which is not possible, but if you add magic code like
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
before startActivity call, it starts on the new task and everything should work just fine :)
how to create an activity that is restricted to time. I would like when I launch my app, an initial activity appears and lasts only for few seconds just to display the app name and the its version and some other info and after a the designated time, the app starts. I have done such thing but the initial activity had had an animation, and when the animation ends then the new activity or the app starts. But, now my initial activity has no animation and I do not know how to keep an activity active/live for 10 seconds, for an example, and when the 10 seconds end, another app starts?
Use a handler to wait (for example 3 seconds) and move on:
private static int SPLASH_TIME_OUT = 3000;
new Handler().postDelayed(new Runnable() {
/*
* Showing splash screen with timer running. This is useful to showcase your app logo/company or something like that.
*/
#Override
public void run() {
// This method will be executed once the timer is over
// Start your app main activity
Intent i = new Intent(SplashScreen.this, MainActivity.class);
startActivity(i);
// close this activity
finish();
}
}, SPLASH_TIME_OUT);
You can use a Timer:
private Timer timer;
#Override
protected void onResume (){
super.onResume();
timer = new Timer();
timer.schedule(new OpenActivityTask(), SOME_TIME_IN_MILLIS);
}
#Override
protected void onPause (){
super. onPause();
timer.cancel();
timer = null;
}
private static class OpenActivityTask extends TimerTask {
#Override
public void run() {
//TODO Go to new activity
}
}
It provides cancellation in case you manually close the activity before the delay time is reached, or if it goes to background for some reason.
Another option is to use the AlarmManager and schedule a one-shot PendingIntent. This approach is probably shorter in code and also allows for safe cancellation:
PendingIntent pi;
#Override
protected void onResume (){
super.onResume();
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, YourOtherActivity.class);
pi = PendingIntent.getActivity(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + SOME_TIME_IN_MILLIS, pi);
}
#Override
protected void onPause (){
super. onPause();
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pi);
}
I want my app to show a notification with a "GOOD MORNING" message at 6 A.M everyday. As I read, for this I need the app to run in background so I need to use Service.
I have tried the following code but I'm stuck.
MainActivity.java
public void onClickStartService(View v)
{
startService(new Intent(this,MyService.class));
}
public void onClickStopService(View v)
{
stopService(new Intent(this,MyService.class));
}
and MyService.java is
public class MyService extends Service{
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
//Note: You can start a new thread and use it for long background processing from here.
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
}
I have buttons to start and stop the Service and it works. Now I want the service to create notification as I have mentioned at the beginning of the post. How can I do this?
To start the service at a specific time, I suggest you create a BroadcastReceiver triggered by an Alarm, which will in turn start your service.
First write a BroadcastReceiver like this :
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
context.startService(new Intent(context, MyService.class));
}
/**
* Schedule the next update
*
* #param context
* the current application context
*/
private static void scheduleServiceUpdates(final Context context) {
// create intent for our alarm receiver (or update it if it exists)
final Intent intent = new Intent(context, AlarmReceiver.class);
final PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// compute first call time 1 minute from now
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 10);
long trigger = calendar.getTimeInMillis();
// set delay between each call : 24 Hours
long delay = 24 * 60 * 60 * 1000;
// Set alarm
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, trigger, delay, pending);
// you can use RTC_WAKEUP instead of RTC to wake up the device
}
}
Then you just need to call the scheduleServiceUpdate method to start the reccuring event. If you only use the RTC type, then if the phone is locked when the alarm should trigger the service, it won't and will wait until the device is unlocked by the user. If you use RTC_Wakeup, the service will start exactly at the time given.
Note that there are other methods in the AlarmManager to trigger events.
You can start from PendingIntent and AlarmManager
Tutorial here
Dont forget to add possibility to cancel alarm manager with
mAlarmManager.cancel(pendingIntent);
Also you may want to intercept android.intent.action.BOOT_COMPLETED event to make you app starting immediately after reboot if you want to start your service by schedule.
I am attempting to use CommonsWare's WakefulIntentService in a new application, specifically its ability to easily schedule the intent service to run at a later time.
I have a PreferenceActivity that allows the user to pick the schedule that the service is run (daily at 5am for example). Once the user makes a change to the preference value, I call:
AutoDownloadIntentServiceAlarmListener alarmListener = new AutoDownloadIntentServiceAlarmListener();
alarmListener.setForcedHour(5); // we want to schedule alarm for 5am everyday.
WakefulIntentService.scheduleAlarms(alarmListener, this, true);
For some reason, the desired IntentService (that extends WakefulIntentService) immediately starts up and performs its work.
Here is the implementation of of AutoDownloadIntentServiceAlarmListener:
public class AutoDownloadIntentServiceAlarmListener implements WakefulIntentService.AlarmListener {
private static final String TAG = "AutoDownloadIntentServiceAlarmListener";
private int mForcedHour = -1;
#Override
public long getMaxAge() {
return AlarmManager.INTERVAL_DAY * 2;
}
public void setForcedHour(int forcedHour) {
mForcedHour = forcedHour;
}
#Override
public void scheduleAlarms(AlarmManager alarmManager, PendingIntent pendingIntent, Context context) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
String autoDownloadTimePref = MyApplication.getInstance().getPrefs().getString("autoDownloadEpisodesSchedule", "0");
int hourOfAlarm = Integer.parseInt(autoDownloadTimePref);
// if this class has been created with a specific hour
// use it instead of the value obtained from SharedPreferences above.
if (mForcedHour > -1) {
Log.w(TAG, "Forced hour has been set for this AlarmListener. " + mForcedHour);
hourOfAlarm = mForcedHour;
}
calendar.set(Calendar.HOUR_OF_DAY, hourOfAlarm);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.d(TAG, String.format("Scheduled inexact alarm for %d", hourOfAlarm));
}
#Override
public void sendWakefulWork(Context context) {
Intent serviceIntent = new Intent(context, AutoDownloadIntentService.class);
WakefulIntentService.sendWakefulWork(context, serviceIntent);
}
}
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day. (and continues to repeat on this schedule indefinitely, or until the user elects to disable or change its schedule)
What am I doing wrong?
It is my intention that the service does not startup as soon as it is scheduled, and instead starts up only at 5am the next day.
Except that's not what your code does, ~80% of the time. Your code says that it should run at 5am today, as you are getting the current time and not changing the day. Most of the time, 5am today is in the past, and so AlarmManager will immediately do its work.
You need to see if your calculated Calendar is older than now, and if so, add a day.