I set an AlarmManager object to start a service.
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); //context = getApplicationContext();
Intent alarmServiceIntent = new Intent(context, AlarmHandlingService.class);
alarmServiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
alarmServiceIntent.putExtra("alarmId", _id); //_id is a "long" value
PendingIntent pi = PendingIntent.getService(context, (int)_id, alarmServiceIntent, 0);
am.set(AlarmManager.RTC_WAKEUP, time, pi);
The onStartCommand(..., ..., ...) of AlarmHandlingService works as it has to work and when it has to work. There isn't any problem:
public int onStartCommand(Intent intent, int flags, int startId)
{
long alarmId = intent.getLongExtra("alarmId", -1);
Intent someActivityIntent = new Intent(this, SomeActivity.class);
someActivityIntent.putExtra("alarmId", alarmId);
someActivityIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(someActivityIntent);
return START_NOT_STICKY;
}
But then, when a new activity is opened (SomeActivity) and I call stopService(...), the service is not stopped:
stopService(new Intent(context, AlarmHandlingService.class)); //context = getApplicationContext();
This is the declaration of my service class in the manifest:
<service android:name="***myPackageName***.AlarmHandlingService"></service>
I tried to debug and noticed only that the registerReceiver (BroadcastReceiver receiver, IntentFilter filter) function of android.content.ContextWrapper class is called when I call the stopService.
From you comments you are not doing anything when your stopService is being called.
When you call stopService it will actually give a call to the function stopService().(which is being done in your application).
You must use onDestroy Method.
public void onDestroy ()
Added in API level 1
Called by the system to notify a Service that it is no longer used and is being removed. The service should clean up any resources it holds (threads, registered receivers, etc) at this point. Upon return, there will be no more calls in to this Service object and it is effectively dead.
(Do not call this method directly).
and the other problem is you are not calling anything to stop your alarm manager.
you must have called cancel method for AlarmManager.
please try with new activity.
stopService(new Intent(this, AlarmHandlingService.class));
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 am trying to call from my BroadcastReceiver(ReceiverSchedule) to call a method (CancelSchedules) in my Activity(ViewScheduleActivity). The main problem I have is that it the Activity becomes null on the onReceive. I think I'm simply passing it into the intent wrong. I have tried the following link: Call an activity method from a BroadcastReceiver class.
First there is an alarmanager that will get called at the correct time then in the Receiver I want to cancel all alarms. Here is the code in the Activity to set the alarm (this part will work fine).
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(this, RecieverSchedule.class);
myIntent.setClass(this, recieverSchedule.getClass());
myIntent.putExtra("scheduleJson", gs.toJson(schedule));
myIntent.putExtra("LoginUserAsString", gs.toJson(loginUser));
myIntent.putExtra("PatientAsString", gs.toJson(patientResult));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, i);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
Toast.makeText(ViewScheduleActivity.this, "Set One Time Alarm at: "+ hour +":" + min, Toast.LENGTH_LONG).show();
Now to pass the Activity over in my BroadCastReceiver I have:
public void setMainActivityHandler(ViewScheduleActivity main) {
viewScheduleActivity = main;
}
with the declaration on top:
ViewScheduleActivity viewScheduleActivity = null;
Now on create I would like to call the method CancelSchedules which is in my ViewScheduleActivity:
public void CancelSchedules()
{
for (int i =0; i< 10; ++i)
{
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(this, RecieverSchedule.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, i);
alarmManager.cancel(pendingIntent);
}
}
In my onReceive in RecieverSchedule I have:
public void onReceive(Context context, Intent intent) {
viewScheduleActivity.CancelSchedules();
}
The problem is that viewScheduleActivity is null causing me to be unable to call it.
I have the following code to pass over the Activity with ReciverSchedule created as a member in the Activity:
recieverSchedule = new RecieverSchedule();
recieverSchedule.setMainActivityHandler(this);
IntentFilter callInterceptorIntentFilter = new IntentFilter("android.intent.action.ANY_ACTION");
registerReceiver(recieverSchedule, callInterceptorIntentFilter);
The setMainActivityHandler will get called and created, but I suspect that I am passing a new RecevierSchedule rather than the set receiverSchdule. If I am correct, how do I pass receiverSchedule into the Alarmmanager? I thought registerReceiver would fix this issue but maybe the placement is wrong.
Your Activity will likely be long killed and dead by the time the AlarmManager triggers your BroadcastReceiver. When that happens, Android will create a new process for your application, instantiate your BroadcastReceiver and call onReceive(). This is why the variable viewScheduleActivity is null.
As #Athena suggested, you don't need to call back into your Activity in order to cancel alarms.
I am using Android AlarmManger to schedule an IntentService to run after small intervals.
Here is my AlarmManger:
static void setNextSchedule(Context ctx, long interval){
AlarmManager manager = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Intent nIntent = new Intent(ctx, DService.class);
PendingIntent pIntent = PendingIntent.getActivity(ctx, 1, nIntent, PendingIntent.FLAG_UPDATE_CURRENT);
manager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + interval, interval, pIntent);
Log.i(ScheduleAlarm.class.getSimpleName(), "Next alarm set");
}
And my IntentService:
#Override
protected void onHandleIntent(Intent intent) {
Log.i(DService.class.getSimpleName(), "Service starting");
ScheduleAlarm.setNextSchedule(getApplicationContext(), 15000);
}
Currently it just holds code for testing. Now this code will run successfully with no problems once the app starts but after 15 seconds it will state that the service is starting in the logcat but the code won't execute.
How to get the intenet service the execute the code inside the onHandleIntent each time it runs?
Thanks
When using a PendingIntent, the factory method needs to match the type of component that your Intent is for:
If your Intent points to an activity, use getActivity()
If your Intent points to a service, use getService()
If your Intent points to a BroadcastReceiver, use getBroadcast()
If your Intent points to none of the above, go directly to jail, do not pass Go!, do not collect $200 :-)
In Android to kill an activity, you just use finish(). But in my case I want to kill the activity when the PendingIntent is fired.
My code is as follow:
Intent intent = new Intent(MainActivity.this, NextActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Utils.KEY_RECORD_TIME, recordLength);
PendingIntent pintent = PendingIntent.getActivity(MainActivity.this,
piNumber, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
If I add finish() beneath, the activity will be killed before the time set up in the AlarmManager.
I want the activity to be visible until the time goes off and kill it. Are there any ways to do this? I did some searches in Stack Overflow, Google but could not find an answer.
Inside a timer you get the time delay of the pending intent.
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
}
},pending intent delay);
Please try this.It work for me
You can register a BroadcastReceiver dynamically in your activity. With the pending intent, you use getBroadcast(). So you can call finish() inside the broadcast receiver when it is invoked by the alarm manager. Note that you must unregister the receiver when you don't need it anymore, you do that in onDestroy() for example.
Look at onNewIntent(Intent). If you can start your activity as a single top, then your instance should receive the pending intent through that call.
If you can't use singel top, and a new instance of your activity is being launched, you could use a shared static to get the original instance in onCreate() of the new one and finish() both.
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.