with a BroadCastReceiver, I execute a service at the smartphone boot:
public class BootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
}
}
MyService:
private Runnable myRunnable = new Runnable() {
public void run() {
parsing.cancel(true);
parsing = new Parsing();
parsing.execute();
handler.postDelayed(this, timeoutUpdate);
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.removeCallbacks(myRunnable);
handler.postDelayed(myRunnable, 1000);
return Service.START_STICKY;
}
The service is really executed at the boot, but if I set a timeout of 1 hour between executions, service is not executed (maybe the system is killing it). Otherwise, if I set 60 sec between repetition, all works.
How can I do it? Thanks.
You may run the service in the foreground using startForeground().
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory.
But bear in mind that a foreground service must provide a notification for the status bar (read here), and that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Note: This still does not absolutely guarantee that the service won't be killed under extremely low memory conditions. It only makes it less likely to be killed.
OR
If you dont want to run the service in the foreground then you can run service in a periodic intervals using AlarmManager
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_HOUR, pintent);
Update
Cancel the registered event by using
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pintent);
To schedule a job use AlarmManager in BroadcastReciever.
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm. setRepeating(AlarmManager.RTC_WAKEUP, triggerInMillis, intervalMillis, pintent);
System will awake your service and then you will be able to execute task immediately.
set highest priority for your service
<intent-filter
android:priority="integer" >
</intent-filter>
The value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.
Related
My ReminderService uses the AlarmManager to inform the user about an upcoming event at a specific time. Is it possible that the AlarmManager informs the same service (ReminderService) or do I need to start another service to catch the pending intent? Until now this mechanism looks like this
public class ReminderService extends Service {
// ...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// ..
/* When the alarm goes off the NotifyService will be started. Is it possible to inform **this**
service (ReminderService) and to handle the alarm? */
Intent alarmIntent = new Intent(this, NotifyService.class);
alarmIntent.putExtra(TodoTask.PARCELABLE_KEY, task);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
Calendar calendar = Calendar.getInstance();
Date date = new Date(reminderTimeStamp*1000);
calendar.setTime(date);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
yes u can. You just need to change this line:
Intent alarmIntent = new Intent(this, NotifyService.class);
to this:
Intent alarmIntent = new Intent(this, ReminderService.class);
that way the ReminderService will receive the intent with TodoTask.PARCELABLE_KEY inside this same method public int onStartCommand(Intent intent, int flags, int startId)
Remember that there no guarantee that this will be the same instance of the service. If the service you're running get killed by the system a new instance of it will be started to handle the intent.
Also remember all the sleep and doze mode stuff mentioned by Larry_Schiefer on his answer.
You can use the same Service (or other component) to receive an alarm. However, not that your alarm will not be guaranteed to be delivered on schedule when in low power. Use a WakefulReceiver or your own combination of BroadcastReceiver and a wakelock to get your Service going. See this article for more details on power state and alarms.
Also, note that starting with Android Marshmallow your wakelocks will be ignored if the device is in Doze mode. There are other things you'll have to do to wake the device at a certain time when in Doze.
I have some existing code that spawns a service intent which does a bunch of stuff in the background. This code does work...
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
My question is: how to change this to use the AlarmManager.setInexactRepeating(...) methods?
I have changed the above code to this:
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.putExtra("STARTED_BY", starter);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Set up recurring alarm that restarts our service if
// it crashes or if it gets killed by the Android OS
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, serviceIntent, 0);
//am.cancel(pi);
am.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP //wake up the phone if it's asleep
, cal.getTimeInMillis()
, 10000
, pi);
And I have added these permissions to AndroidManifest.xml...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="com.android.alarm.permission.WAKE_LOCK"/>
My understanding is that this is supposed to start the service immediately and then try to restart it again every 10 seconds. But this code isn't working properly.
Using this new code, the service never starts at all and I cannot see why not. To complicate matters the debugger never seems to attach to the app in time to see what's going on.
Can anyone see what I'm doing wrong?
Put AlarmManager code under onDestroy() function of service to schedule start of service as below:
#Override
public void onDestroy() {
/**
* Flag to restart service if killed.
* This flag specify the time which is ued by
* alarm manager to fire action.
*/
final int TIME_TO_INVOKE = 5 * 1000; // try to re-start service in 5 seconds.
// get alarm manager
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AutoStartServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// set repeating alarm.
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
TIME_TO_INVOKE, TIME_TO_INVOKE, pendingIntent);
}
And handle starting of your service in AutoStartServiceReceiver as below:
public class AutoStartServiceReceiver extends BroadcastReceiver {
private static final String TAG = AutoStartServiceReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
// check broadcast action whether action was
// boot completed or it was alarm action.
if (intent.getAction().equals(AppConstants.ACTION_ALARM_INTENT)) {
context.startActivity(new Intent(context, YourActivity.class));
// handle service restart event
LockerServiceHelper.handleServiceRestart(context);
}
}
}
Kindly note that, your service will not restart if you stop it manually from settings-apps-running apps-your app.
Your service is not starting because of AlarmManager.ELAPSED_REALTIME_WAKEUP, while it should be using AlarmManager.RTC_WAKEUP
If you want to run every 10s keep in mind that above API 21 alarm intervals below 60s are rounded up to 60s.
Also, consider using WakefulIntentService
https://github.com/commonsguy/cwac-wakeful
I need to run a service in time interval, for example every 2 minutes. I register it with AlarmManager, it works fine when the service stops itself before that 2 minutes is up, but there is a great chance it will take more than 2 minutes, in this case I'll need the service to be terminated and start up a new one, how can I do this?
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), Sender.class);
PendingIntent pi = PendingIntent.getService(getApplicationContext(), 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),1000 * 30, pi);
Instead of starting service by AlarmManager use broadcast. Set AlarmManager to send some broadcast intent. Create your own BroadcastReceiver that will receive that intent and in onReceive method restart(stop and start) service.
//Start AlarmManager sending broadcast
Intent intent = new Intent(context, MyBroadcastReceiver.class); // explicit
peningIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 30 * 1000, pendingIntent);
.
//BroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(SynchronizationService.class.getName());
context.stopService(serviceIntent);
context.startService(serviceIntent);
}
}
.
//Register receiver in AndroidManifest.xml in Application tag
<receiver
android:name="com.example.MyBroadcastReceiver" >
</receiver>
You should write a login in onStartCommand itself.
Check if service is running or not using variable.
If its running call stopSelf method on service,then again call startservice for same service.
start a alarm manager services u have to use this code
Intent intent = new Intent(activity.this,Sender.class);
pendingIntent = PendingIntent.getBroadcast(activity.this.getApplicationContext(),1, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),1000 * 30, pendingIntent);
for stop this broadcast receiver use this code
Intent intent = new Intent(activity.this,Sender.class);
pendingIntent = PendingIntent.getBroadcast(activity.this.getApplicationContext(), 1,intent, 0);
pendingIntent.cancel() ;
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);
I've been struggling with this for a couple of days. What I want to do is run a service periodically, about 2-3 minutes apart. I have an Activity that is responsible for the interface and setting up the first alarm.
The alarm is configured by a BroadcastReceiver which looks like this:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
setAlarm(context);
}
public void setAlarm(Context context){
AlarmManager am = (AlarmManager) context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (1000 * 30) , pi);
}
}
I've tried using setRepeating for AlarmManager, but it still has the same effect. What happens is that the AlarmManager works how it should, it fires an Intent which the receiver gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send. Thus, I opted out to setting the alarm every time so I can set pendingIntent flag for updating every time.
I tried making my service an intentService, which is fine, but then my bluetooth scanner inside the service does not work because intentService thread terminates without waiting for my bluetooth discovery to finish.
Anyone have any idea what can help me?
Here is part of my service:
public class DiscoveryService extends Service {
public void onCreate() {
super.onCreate();
Toast.makeText(this, "MyAlarmService.onCreate()",
Toast.LENGTH_LONG).show();
findEverything();
}
}
EDIT: This is the code that I currently have.
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
}
public void setAlarm(Context context){
// get a Calendar object with current time
AlarmManager am=(AlarmManager)context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
(1000 * 30) , pi);
}
What happens is that the AlarmManager works how it should, it fires an Intent which the reciever gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
You are calling startService() once when you are scheduling the alarm. You are not calling startService() at all from your BroadcastReceiver. Yet you are scheduling the alarm via the BroadcastReceiver. Hence, when the alarm goes off, the service will not be sent a command, because you are not sending it a command.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send.
That is only if you use FLAG_ONE_SHOT.
Anyone have any idea what can help me?
Call startService() from your onReceive() method, instead of from your setAlarm() method. Also, add in all the WakeLock management logic, since you are using a _WAKEUP alarm and you are not able to use my WakefulIntentService.