I have a big problem with my app for several days now. I appologize if my english is not so native in advance. I implemented an AlarmManager to give the user of my app the option to start a certain service at any time of the current or the next day. So e.g. the user might choose to set the time for my service to tomorrow at 08:00 a.m. and then starts the service.
The alarm manager should now wait the calculated time from now till the chosen time (i calculated the time also manually and it is correct!) and then start the service. My problem now is that sometimes the alarmmanager is starting my service and somtimes not. It seems that if it has to wait for lets say more than 4 hours it is not working any more and my service is not called. I have set all neccessary permission otherwise it would not work at all. You can have a look at the code of the alarmmanager below:
someIntent = new Intent();
someIntent.setAction("START_SERVICE");
AlarmManager alarams ;
alarmIntent = PendingIntent.getBroadcast(MainActivity.this, 0, someIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarams = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarams.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+delay, alarmIntent);
The broadcast receiver is implemented like this (and it is registered!):
alarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(MainActivity.this, MyService.class);
startService(myIntent);
}
};
As I told you, if it is not working it stops before starting the service.
EDIT:
I have an idea. I read something in this thread: Android long running service with alarm manager and inner broadcast receiver
It might be, that my constructor for the intent "someIntent" only works for BroadcastReceivers declared in the manifest file. So in my case I should maybe use someIntent = new Intent("START_SERVICE") instead of someIntent = new Intent(); someIntent.setAction("START_SERVICE"). This effect is called tunneling - i will figure it out, if it works i will post my experience here. Thanks for the well explained answer on the mentioned thread! If you have any other ideas or the same experiences like me please let me know!
eMu
If the device is shutdown and start up then you will not get the alarm maanger broadcast receiver.
Implement OnBootReceiver which will receive the OnBoot completed and there you can start your pending alarms that were not fired.
Related
Following code works perfectly for Activity:
Intent intent = new Intent(context, MyActivity.class);
PendingIntent operation = PendingIntent.getActivity(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
However, when I do the same thing for IntentService, It works only if startTime and time I set alarm are on the same day. e.g. If I set the alarm today for 5 PM, it will be executed but when I set the alarm today for 5 PM tomorrow, it will not be executed. If this was Activity then it works for both cases.
Intent intent = new Intent(context, MyService.class);
PendingIntent operation = PendingIntent.getService(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
How to solve this?
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
Google has made this progressively harder from release to release. See Android AlarmManager setExact() is not exact. There could be two ways to solve this for your case:
you start an activity, which starts the service (as starting an Activity seems to work for you)
you use either setExactAnd... or setAlarmClock. setAlarmClock also triggers in the new "doze" mode, see https://stackoverflow.com/a/47049705/1587329.
Another way would be to re-think why and if you really need this... or if a JobScheduler could not fit your purpose more easily.
add replace your line with this line :
alarmmanager.setRepeating(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
it will repeat on specific interval you set in alarm manager
Replace the AlarmManager with this code:
alarmManager.setRepeating(AlarmManager.RTC,
timeMills,
AlarmManager.INTERVAL_DAY,
pendingIntent);
Worked for me.
HERE IS a DETAILED ANSWER check link in the bottom for more details.
Hope this will help. Your issue can be probably related to android versions too so do check the link for more details
app gets an instance of the AlarmManager and sets an alarm using a PendingIntent. More on usage and setting alarms is coming in the next section. The AlarmManager is the app side interface to the backing AlarmManagerService. It abstracts the details of the Binder interface, used to communicate with the system process (system_server) hosting the AlarmManagerService. These two components manage the alarm(s) the app has set and will send the PendingIntent correctly. This manager/service architecture is used throughout Android framework and is done for security and isolation purposes. The system_server process is running with privileges which normal apps do not have. If you are unfamiliar with Android’s use of permissions, see this article for more details on app processes and user IDs. These extra permissions are what allows system_server to access the underlying kernel alarm driver. The alarm driver is what manages setting alarms to wake up the device regardless of the sleep state of the SoC.
When the alarm is triggered the device is awakened (if asleep) and the AlarmManagerService is notified of an alarm expiring. It will then send the PendingIntent accordingly. This will cause the appropriate component within MyApp to be activated. If MyApp has not been started or its process is not cached, it will be started so the component can be activated.
basic usage will be as
public class MyActivity extends Activity {
...
private AlarmManager mAlarmMgr;
...
public void onCreate(Bundle savedInstance) {
...
mAlarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
...
}
...
}
let’s create a PendingIntent for our MyActivity using the component name.
Intent alarmIntent = new Intent(context, MyActivity.class);
PendingIntent pend = PendingIntent.getActivity(context,
0,
alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Now that we have our PendingIntent and the AlarmManager, we can set our alarm so our Activity is triggered when the alarm has expired. To do this, we need to figure out when we want our alarm to go off and whether it should wake up the device or just be delivered the next time the device is awakened. Remember, we have two different ways of specifying time for our alarms: elapsed time or calendar (RTC) time. So our options are ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or RTC_WAKEUP. The _WAKEUP variants are our “aggressive” alarms where we want the device to come out of low power to call our app back. For our sample app, let’s set this up in a custom BroadcastReceiver and have it trigger our Activity about 30 seconds after the device is booted
public class MyBootReceiver extends BroadcastReceiver {
public void onReceive(Context, context, Intent intent) {
...
AlarmManager alarmMgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
long wakeTime = SystemClock.elapsedRealtime() + 30000;
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeTime, pend);
}
}
Now when our device boots and the BOOT_COMPLETED broadcast is sent, our app’s process will be started and our receiver will set an alarm to trigger our Activity to be launched about 30 seconds later. Note that on Android 3.1 devices or newer, you must first manually launch your app before the BOOT_COMPLETED.
CREDIT GOES to writer of this BLOG
if you want to set the repeated alarm using SetExact you are bound to stop all other pending intents on the same time check this link for that here are many examples of how to do it! again credit goes to this writer
I'm usign an Alarm Manager to update a widget with a Service. I've two different questions.
First question: I'm calling the service with Alarm Manager's intent. Like this:
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyService.class);
pi = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
context.startService(new Intent(context, MyService.class));
Long repeat = Long.parseLong(prefs.getString("update_preference", "600"));
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), 1000*repeat, pi);
Is it wrong?
It looks and works right. But when I have looked at working services, I can't see my service name in the list. Perhaps it's not running as a single/seperate service. Just saw application name (not as a service). I'm not sure how to seperate or does it matter?
Another question: Over long time, running application, which controls widgets update, is closed somehow (manually or by a task killer). Of course Alarm Manager gonna stop and widget's functions gonna stop too. For example button clicking.
But, Twitter solved this problem. While the widget is active, if I close the main application (Twitter) -which controls widget- than click the widget, somehow widget triggering application and it starts again well. So buttons work properly. How is that possible?
Any help would be appreciated.
You dont need to do context.startservice that what the pending intent is for, if you want the service to run right away the first time just set it to run at the current time then set the interval from the current time.
You are also setting 2 different types of repeating when you don't need to setRepeating is strict where setInexact is not and can be adjusted by the OS when it gets fired hence the inexact in it. You want one or the other not both.
Also those intervals are very small and its going to kill the battery significantly.
It should just be this
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyService.class);
pi = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
Long repeat = Long.parseLong(prefs.getString("update_preference", "600"));
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
Calendar.getInstance().getTimeInMillis(), 1000*repeat, pi);
It's good that your application/service isn't running all the time.
In fact it doesn't need/has to run all the time for updating a widget. If you schedule an Intent with AlarmManager the application will be started when the intent is fired if it has been closed.
My intention is to make an application that will track the movement of my android phone for every few minutes and send it to my server. I have read a lot online on how to do it with a service, AlarmManager and Partial_WakeLock. I have also gone through the commonsware examples in github.com but I was a bit confused because I am still not experienced in android.
I have been successful in getting my application to [get location and send it to my server]. How do I make my service wakeup every few minutes and do [work mentioned]? In the Wakeful example in commonsware, in which method do I mention my [work] and in which method do I keep calling it?
You need a Service and an AlarmManager. Your Service will handle getting the position and posting it to the server and AlarmManager will invoke your service basen on an interval you decide. You should initialize your AlarmManager with your Service roughly like this in onCreate or other place you want:
AlarmManager alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, YourAlarmReceiver.class),PendingIntent.FLAG_CANCEL_CURRENT);
// Use inexact repeating which is easier on battery (system can phase events and not wake at exact times)
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, YOUR_ALARM_TRIGGER_AT_TIME,YOUR_ALARM_INTERVAL, pendingIntent);
YourAlarmReceiver gonna start your service
public class YourAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, YourService.class));
}
}
On how to use Services refer to the android website http://developer.android.com/guide/topics/fundamentals/services.html
you could use a partial wakeLock with a sleep(X) which when the sleep(x) is resolved the system will call the next line of code, but the problem is I am seeing a possible infinite cycle that might need a task kill action, or just crash the system.
I have created an On Boot Receiver to repeatedly call a wakeful intent service every 5 minutes but cannot figure out how to start the service immediately when the app is installed..? I do not want to rely on the user rebooting their device before it starts to run!
Here is my code so far :
public class OnBootReceiver extends BroadcastReceiver {
private static final int PERIOD = 300000; // check every 5 minutes
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60000, PERIOD, pi);
}}
Can anyone help me out pls? :)
If you want to set an alarmmanager to start your service when the app is installed, then it's not possible. It's a OS limitation, security if you will. But if you want to start the service in the moment the app starts, just call it, it will keep runing.
Essentially, since the Application object is created when the application is started and when the BOOT_COMPLETED Intent is received, you could register with the AlarmManager in the onCreate method in your custom Application class. Just be aware that the Application object is instantiated every time the process starts, which includes cases where the process is temporarily killed to save resources. But if you don't change the PendingIntent in any way, it should be no problem to register over and over again.
However, it is not possible to start the application when it is installed, there has to be some user interaction first.
I need to have a process run whenever the end-user clicks on a Submit button. The application needs to try to process the data on the screen every X minutes, Y times, even if the the application is down. So, it will need to attempt to do some processing until one of the following occurs:
1) The processing is successful for the data that was submitted
2) The processing has been retried Y times and still never succeeded
3) The application is terminated by the OS or the phone is turned off.
If the end-user's phone is still on but the application has stopped,
what's the correct interface to use to accomplish this?
If I use Handler/Runnable, that only works as long as the application stays active.
AlarmManager looks like it's used when you want processing to run at a specific time.
Any suggestions will be greatly appreciated!
I use this method to set an alarm.
private void setAlarm(){
Context context = getApplicationContext();
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
myCal = Calendar.getInstance();
myCal.setTimeInMillis(myPrefs.getLong("time", 0));
mgr.set(AlarmManager.RTC_WAKEUP, myCal.getTimeInMillis(), pi);
Log.i(myTag, "alarm set for " + myCal.getTime().toLocaleString());
Toast.makeText(getApplicationContext(),"Alarm set for " + myCal.getTime().toLocaleString(), Toast.LENGTH_LONG).show();
}
inside my onAlarmReciever onRecieve method is this:
Intent i = new Intent(context, AlarmActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
So basically when the intent fires it starts the AlarmActivity. Inside that activity you could have it try what ever you are doing and if it fails call the setAlarm() again
You have two options: a Service, or set up an alarm with AlarmManager. Which one you pick will depend mostly how often do you want to retry. A minute? Use a service. An hour? A day? set up an alarm so you don't waste the phone resources keeping the service alive.
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/reference/android/app/AlarmManager.html
Write an Android Service