I have made a simple example where a toast message will be shown after a time gap. I am using alarmmanager for scheduling a service from where the toast message will be shown. Now the problem is when the app is running it works properly, but when I close the app from task-manager the service is not getting restarted. Below is my service code
public class AlarmService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Alarm Alarm Alarm", Toast.LENGTH_SHORT).show();
return Service.START_STICKY;
}
}
and below is my alarmmanager code :
alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmService.class);
pendingIntent = PendingIntent.getService(this, 0, intent, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 10, pendingIntent);
Now, what is the solution for this? I need to keep the alarm even I close the app.
You can actually implement BroadcastReceiver at onDestroy to restart the service once the app/service is close by the system/user.
You can check the post here, and a tutorial for you, check here.
Hope it helps!
Try with below :-
return Service.START_CONTINUATION_MASK;
Related
I am trying to create a SMS-app which sends out SMS at one set time of day. For this I have created two services SendMessagePeriodicService and SendMessageService.
This is my SendMesagePeriodicService, which is supposed to trigger SendMessageService at a set time of day. The problem is that it triggers every time the onStartCommand-method is called...
public class SendMessagePeriodicService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) { //FIXME
Calendar cal = Calendar.getInstance();
Intent i = new Intent(this, SendMessageService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
cal.set(Calendar.MINUTE, PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getInt("minute", -1));
cal.set(Calendar.HOUR_OF_DAY, PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getInt("hour", -1));
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pintent);
return Service.START_NOT_STICKY;
}
}
I have also checked that the values in the sharedPreferences are correct...
Does anyone have any idea why this is happening?
I would do that by setting the alarmmanager in the activity and than use BroadcastReceiver to send the sms when the alarm fires.
I use the same technique to start a notification on a specific time.
I think I have read somewhere the you use services nowadays only for fileoperations. But I´m not 100%.
It seems that the reason this happens was that the time I set for trigger time was in the past. This means that AlarmManager triggers immediately and not the next time this set time occurs.
Hi a read other question retated to this but the responses never resolve my issue.
I want to start a service after a specific time with an Alarm Manager
alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmServiceIntent=new Intent(ListActivity.this, AlarmLevelServiceImproved.class);
alarmServiceIntent.putExtra("username",usernameID);
alarmServiceIntent.putExtra("password",userPass);
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmServiceIntent, 0);
. . .
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND,10);
//calendar.set(Calendar.HOUR_OF_DAY, 19);
//alarmMgr.setInexactRepeating(AlarmManager.RTC,calendar.getTimeInMillis(),
// AlarmManager.INTERVAL_HALF_HOUR,alarmIntent);
//alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
// 1000 * 10, alarmIntent);
alarmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);
Log.d("MioLog", "Alarm setted");
My service is:
public class AlarmLevelServiceImproved extends Service {
#Override
public void onCreate() {
Log.d("MioLog","MyAlarmService.onCreate()");
Toast.makeText(this, "MyAlarmService.onCreate()", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
Log.d("MioLog","MyAlarmService.onBind()");
Toast.makeText(this, "MyAlarmService.onBind()", Toast.LENGTH_LONG).show();
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("MioLog","MyAlarmService.onDestroy()");
Toast.makeText(this, "MyAlarmService.onDestroy()", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MioLog","MyAlarmService.onStart()");
Toast.makeText(this, "MyAlarmService.onStart()", Toast.LENGTH_LONG).show();
return super.onStartCommand(intent, flags, startId);
}
}
And I add this on AndroidManifest.xml (The service class is on the sub-package "services"):
<service
android:name=".services.AlarmLevelServiceImproved"
android:enabled="true" />
But the service don't start and no log is printed.
Any idea how to start a Service with the AlarmManager?
I also suived this tutorial but I don't find any difference to my code
Thanks
To start a service with a PendingIntent, you need to use the static method PendingIntent.getService() to retrieve the appropriate PendingIntent.
Your code seems to be using PendingIntet.getBroadcast() for whatever reason. If you intend to have the AlarmManager indeed send a broadcast, you can start your service in your BroadcastReceiver, else change that line to getService():
from
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmServiceIntent, 0);
to
alarmIntent = PendingIntent.getService(getApplicationContext(), 0, alarmServiceIntent, 0);
You are using getBroadcast() to create the PendingIntent, but the Intent points to a service. That combination will not work.
Since you are using RTC_WAKEUP, you need to use getBroadcast() and a WakeLock to get reliable results. One approach is to use WakefulBroadcastReceiver as the base class of your receiver, where you then forward the work onto an IntentService.
Also, please do not pass user names and passwords in extras, as those are visible to anything that gets its hands on the Intent or PendingIntent. In this case, that should just be your app and the core OS, but I would still aim to do something a bit more secure.
I've various options to sync data between android app and server. I'm using AlarmManager to trigger sync with user choices. I've one which says Never Update (Update Manually) in which i cancel with toStopServiceAlarm() the AlarmManager.
Que:
It's working fine as long as my application won't be killed by any task manager. As soon as it's killed by Task Manager application service again started with Never Update(Update Manually) where i already cancelled any AlarmManager trigger.
Can anybody help me in preserving my application behaviour even if it's killed by Task Manager? Sync get called as per user choice only.
Code Snippet:-
public class ServiceAlarm extends WakefulBroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, UploadData.class); //UploadData is my service
startWakefulService(context, service);
}
public void startServiceAlarm(String times)
{
context = SmartConsultant.getApplication().getApplicationContext();
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(SmartConsultant.getApplication().getApplicationContext(), UploadData.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 21);
calendar.set(Calendar.MINUTE, 00);
switch(Integer.parseInt(times))
{
case 0://midnight
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
break;
... cases for different interval of sync
}
}
public void toStopServiceAlarm(String times)
{
if (alarmMgr != null) {
alarmMgr.cancel(alarmIntent);
}
}
As per CommonsWare, I just need to override onStartCommand() with START_NOT_STICKY which will make my service loosly tight with Android and won't start once it's killed by TaskManager. That's what behaviour expected from that running Service.
Code Snippet:
public class UploadData extends Service
{
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
super.onStartCommand(intent, flags, startId);
return START_NOT_STICKY;
}
}
So I have a section of code that schedules an alarm as follows
public void scheduleAlarm(){
Log.d("Scheduler","Alarm is being scheduled");
Intent intent = new Intent(AlarmSettings.this, VolumeService.class);
intent.putExtra("MODE", mode);
PendingIntent pintent = PendingIntent.getService(AlarmSettings.this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Log.d("Alarm ID:", String.valueOf(id));
Log.d("Time", "Time was set for today: " + String.valueOf(time));
if(time < System.currentTimeMillis()){
time += (DAY);
Log.d("Time", "Time was set for tomorrow: " + String.valueOf(time));
}
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP, time, pintent);
}
The service that is being called is as follows
public class VolumeService extends Service{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//My Service code goes here and makes changes to some settings
Log.d("Service", "settings have been changed");
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
and finally the portion of code that is supposed to cancel the alarms (stay with me, I know its lengthy)
//Unschedule the alarm that is getting deleted
Log.d("Unscheduler", "Alarm is being unscheduled");
Intent uIntent = new Intent(AlarmSettings.this, VolumeService.class);
PendingIntent uPintent = PendingIntent.getService(AlarmSettings.this, id, uIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager uAlarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
uAlarm.cancel(uPintent);
uPintent.cancel();
Now, my problem is that when the user deletes an alarm and subsequently calls the unschedule portion of the code, the volumeService is immediately called and the settings are changed. However, this defeats the purpose of the user deleting the alarm as they will only delete it to prevent it from firing and changing the settings. I have checked everywhere imaginable over the course of weeks and am just beating my head against the wall. Now that I have posted it on here though, it will be that I have made a very simple mistake. In any case, thanks for the help in advance!
--edit #1--
Removed the line uPintent.cancel() in the unscheduler portion and still doesn't work.
I am having a problem with trying to schedule my service to run every so often. I have gotten my service to start on boot, but for what ever reason when the schedule starts is starts the service way to many times.
public class PPPService extends Service {
public void onStart(Intent intent, int startId) {
//TODO do something useful
Log.v("TEST", "Service started");
// Schedule the alarm!
PendingIntent mAlarmSender = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, AlarmManager.INTERVAL_FIFTEEN_MINUTES, mAlarmSender);
this.stopSelf();
}
}
Resolved: This was resolved by creating a Scheduler instead of having my service schedule itself.
You are sending in the PendingIntent the context of your service that will be killed very soon along with the intent which started it. I guess this can be quite unpredictable. Try getting the pending intent like this:
mAlarmSender = PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), PPPService.class), 0);