I start AlarmManager with PendingIntent and on few phones Alarm is not responding. On some devices is working ok on others it fails. I have made a few tests on different phones.
Nexus works ok, also Samsung Galaxy S4 zoom (4.2) works ok.
Samsung note 2 (4.3) works ok.
OPPO (4.4.4) alarm dies.
I have also implemented broadcast receivers which are working as they should on all devices.
Log.v(TAG, "START ALARM");
Intent intentAlarm = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 1000, 5000, pendingIntent);
Check whether the app is in stopped state.When the app is in stopped state it wont receive any alarm or events.
Also, I guess it might be OEM/manufacturer specific firmware/OS issue.To check whether the alarm has being actually schedule use adb shell dumpsys alarm and check whether your app alarm has being actually scheduled.
To check whether it is in stopped state use the following command:
adb shell dumpsys package "com.package.name" and check
"stopped=true"
To know more about stopped state refer:
Launch controls on stopped applications
Starting from Android 3.1, the system's package manager keeps track of
applications that are in a stopped state and provides a means of
controlling their launch from background processes and other
applications.
Note that an application's stopped state is not the same as an
Activity's stopped state. The system manages those two stopped states
separately.
The platform defines two new intent flags that let a sender specify
whether the Intent should be allowed to activate components in stopped
application.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped
applications in the list of potential targets to resolve against.
FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped
applications from the list of potential targets. When neither or both
of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential
targets.
Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all
broadcast intents. It does this to prevent broadcasts from background
services from inadvertently or unnecessarily launching components of
stoppped applications. A background service or application can
override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES
flag to broadcast intents that should be allowed to activate stopped
applications.
Applications are in a stopped state when they are first installed but
are not yet launched and when they are manually stopped by the user
(in Manage Applications).
Please note stopped state is different from app process not running.
There could be a couple of different issues at work here:
The type of alarm you are requesting (ELAPSED_REALTIME) will not wake up the device to deliver the alarm. Instead, if it expires while the device is sleeping it will be delivered the next time the device wakes.
The triggerAtMillis value of 1000 is requesting the first alarm at 1 second after boot of the device. If the device has already been up and running and you request this alarm, the first alarm may not fire and could cause the subsequent ones to not get scheduled. This is just a guess, I've not verified by looking at the 4.4.4 AOSP sources
The alarm handling was changed in API 19 (Android 4.4) to handle collating of alarm timers (all are inexact by default) and this change could have affected things for the 2nd bullet. You might try changing the triggerAtMillis value to be (SystemClock.elapsedRealtime() + 1000)
Note that if you need the device to wake from sleep, you'll need to use a _WAKEUP alarm variant and also have your BroadcastReceiver take a wake lock which your Service or Activity releases when it is done handling the alarm.
This is only a guess but I think the issue has to do with the API. Starting with KitKat, the system messes up the AlarmManager. Perhaps consider trying using something else for systems at abd above kitkat.
"Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested. "
Taken from http://developer.android.com/reference/android/app/AlarmManager.html
Your alarms will continue to exist after your app is closed normally. If it is force stopped, or your device restarted, or an update for your app is installed, or your app is uninstalled, they will be lost. You can create BroadcastReceivers for some of those situations to recreate your alarms.
Also, setInexactRepeating is exactly that: inexact. When that alarm fires is implementation dependent and can not be precisely predicted.
Try the following:
1) Add teh Wake_lock permission to your manifest.
<uses-permission android:name="android.permission.WAKE_LOCK">
2) Change
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 1000, 5000, pendingIntent);
with
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, 5000, pendingIntent);
Could you show us the AlarmReceiver.class code?
Maybe you need to use return START_STICKY; on your onStartCommand method?
Try to place AlarmManager into background service.
i have also used Alarm Service in my project for preparative task in very 6 or 7 minutes. And it is running fine in all phone.
i have make a alarm Service like this:
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
public class MyAlarmService {
private static PendingIntent resetAlarm;
private static String TAG="CellPoliceChildGPSAlarmService";
private static AlarmManager am;
public static void start(Context context) {
try {
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
// Create an IntentSender that will launch our service, to be scheduled with the alarm manager.
//resetAlarm = PendingIntent.getService(context, 0, new Intent(context, Get_NonRootDetails.class), 0);
resetAlarm = PendingIntent.getService(context, 0, new Intent(context, CallNonRBackgroundService.class), 0);
// Schedule the alarm!
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Log.i(TAG, firstTime+"");
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, 10*1000*60, resetAlarm);
}
catch (Exception e) {
Log.v("CellInfo", "Exception while start the MyAlarmService at: " + e.getMessage());
}
}
public static void stop(Context context) {
try {
// When interval going to change from web services
am.cancel(resetAlarm);
}
catch (Exception e) {
Log.v("CellInfo", "Exception while start the MyAlarmService at: " + e.getMessage());
}
}
}
I have called or start like this;
MyAlarmService.start(SplashActivity.this);
Given permission in Manifest:
<uses-permission android:name="android.permission.WAKE_LOCK">
<service
android:name="com.secure.DataCountService"
android:enabled="true" >
<intent-filter>
<action android:name="com.secure.MyService" />
</intent-filter>
</service>
For notifications i also used pending intents like;
Intent notificationIntent = new Intent(context, DashBoardActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, PushNotificationUtils.notiMsg, pendingIntent);
notification.flags |= notification.FLAG_AUTO_CANCEL;
Try this it works when activity is not running..
Calendar calendar = Calendar.getInstance();
long timemills = calendar.getTimeInMillis();
Intent myIntent = new Intent(this, TimeChangeReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, timemills, pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, timemills,
10000, pendingIntent);
Related
I am using AlarmManager to call a function at a certain time. It is working successfully in Genymotion Emulator but not in a real device like Redmi, Honor, etc. Here is the Code.
Intent intent = new Intent(CreateContact.this, DeleteContactReceiver.class);
intent.putExtra("name", name.getText().toString());
intent.putExtra("phone", phoneNumber.getText().toString());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getApplicationContext(), (int) System.currentTimeMillis(), intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (selected * 60000), pendingIntent);
The min SDK version is 21.
EDIT: I tried to use setAndAllowWhileIdle but it still won't work.
Any Suggestions?
Use instead the androidx WorkManager library, is the replacement for all scheduling services.
The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs
https://developer.android.com/topic/libraries/architecture/workmanager
What the WorkManager does is to wrap all the existing scheduling services, and use the most appropriate one according to what is available, API level, etc., even taking care of compatibility issues and system bugs.
Some tutorials:
https://medium.com/androiddevelopers/introducing-workmanager-2083bcfc4712
https://www.programmersought.com/article/82731596284/
https://medium.com/swlh/periodic-tasks-with-android-workmanager-c901dd9ba7bc
On certain devices (particularly low-end and Chinese manufacturer), apps are not permitted to perform background functions (if the app is not running) unless the user explicitly enables this. This is to prevent rogue apps from using up the battery by performing background activities.
To get around this, you need to manually add your app to the list of "protected apps" or list of apps that "are allowed to run in the background". To add your app to this list, you need to go to the appropriate setting. This is different on different devices, but it is usually found in either the "power management" or "security" settings.
On Honor devices it is found in "Battery Manager->Protected Apps"
For Xiaomi devices, see https://dontkillmyapp.com/xiaomi
I used this function to make a change in my application daily.
Added Broadcast receiver in Manifest.xml
<receiver android:name=".AlarmReceiver">
<action android:name="alarm.running"/>
</receiver>
MainActivity.java
public class MainActivity extends AppCompatActivity {
AlarmManager alarmMgr;
PendingIntent alarmIntent;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context=MainActivity.this;
AlarmReceiver mScreenStateReceiver = new AlarmReceiver();
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction("alarm.running");
registerReceiver(mScreenStateReceiver, screenStateFilter);
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("alarm.running");
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 36);
// setRepeating() lets you specify a precise custom interval--in this case,
// 1 day
alarmMgr.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis()/1000,
AlarmManager.INTERVAL_DAY, alarmIntent);
}
}
AlarmReceiver.java // A broadcast receiver to show toast for sample
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()){
case "alarm.running":
Toast.makeText(context, "alarm ran", Toast.LENGTH_SHORT).show();
}
}
}
Use the method setExactAndAllowWhileIdle() instead of set() for an action to be triggered precisely in a specific time. However, make sure not to use it regularly unless it's a task worth compromising system resources.
Applications are strongly discouraged from using exact alarms unnecessarily as they reduce the OS's ability to minimize battery use.
Read more AlarmManager | Android Developers - setExactAndAllowWhileIdle
Beginning with API 19 alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. So, from above 19 you can use setWindow method as stated in official document at here.
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 have an alarm to reset a data connection say every 15 minutes. The problem is, once the phone is rebooted, the application gets killed and the alarm (service) doesn't trigger anymore.
(This is not a duplicate, the other similar questions on SO do not solve my problem.)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.sang.mobiledata.ResetBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Broadcast Receiver:
public void onReceive(Context context, Intent intent) {
// if(CONN_ACTION.equals(intent.getAction())) {
if (intent.getAction().equalsIgnoreCase(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE")) {
MainActivity objMain = new MainActivity();
objNetwork.setMobileDataEnabled(context, false);
objNetwork.setMobileDataEnabled(context, true);
}
if (intent.getAction().equalsIgnoreCase(
"android.intent.action.BOOT_COMPLETED")) {
// code to restart/resume/retain alarm
Code to fire alarm (on the onClick):
Intent myIntent = new Intent(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE");
myIntent.putExtra("FLAG_KEY", false);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
long interval = intHrs * 3600000 + intMins * 60000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), interval, pi);
long mins = interval / 60000;
Toast.makeText(
MainActivity.this,
"Data Connection will be reset every " + mins
+ " minute(s).", Toast.LENGTH_SHORT).show();
}
Any suggestions please?
Read the AlarmManager document, there it is written, that AlarmManager will not hold alarms after reboot.
As per the Android Developers,
.... Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
And regarding BOOT_COMPLETED, they write:
... This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.
As for permission is concerned, you have already registered that. Well what probably happening is, the service BOOT_COMPLETED is being used locally, with the application. The reboot of the mobile is system activity, which is not overridden to accomplish re-registry of the alarms being saved. But I am not sure. So, you need to do something when execution comes in hand of BOOT_COMPLETED.
Read Automatically starting Services in Android after booting, this might help you with it.
What I did was, I registered all the alarms and formed a database, using SQLite; On restart, I use to reset all the alarms. Well that worked for me. If you want to go with my process then,
Make a database for your alarms, and save them there. Write your application in such a way that, when the phone restarts, the AlarmManager resets all the alarms. This is how it works.
In Automatically starting Services in Android After booting again. It is written:
Also note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.
I have a scheduler kind of app that sends a notification to the user at a specified time in the morning and in the evening. I have done this using Alarm Manager. On the emulator the application works just fine as far as this is concerned. However in my device I use "Advanced Task Killer" application to kill running apps and free the device's memory. I noticed that on killing this application the notifications are not shown at the scheduled time. This definitely seems logical but is not at all what I want. I want the notifications to be shown at the scheduled time even though the process is killed. Is there a way to do so?
I figured a little bit of code might be helpful to realize my problem :
I have this in my Main Activity
public void setAlarm(){
Intent intent = new Intent(MainActivity.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.cancel(pendingIntent);
Cursor tempcursor = db.getAlarmTime();
tempcursor.moveToFirst();
int hour = tempcursor.getInt(tempcursor.getColumnIndex("Hour"));
int minute = tempcursor.getInt(tempcursor.getColumnIndex("Minute"));
tempcursor.close();
db.close();
GregorianCalendar alarmtime = new GregorianCalendar();
alarmtime.set(GregorianCalendar.HOUR_OF_DAY, hour);
alarmtime.set(GregorianCalendar.MINUTE, minute);
alarmtime.set(GregorianCalendar.SECOND, 0);
alarmtime.set(GregorianCalendar.MILLISECOND, 0);
if(alarmtime.before(new GregorianCalendar()))alarmtime.add(GregorianCalendar.DAY_OF_MONTH, 1);
am.set(AlarmManager.RTC_WAKEUP, alarmtime.getTimeInMillis(), pendingIntent);
}
And this in my AlarmReceiver class that extends BroadcastReceiver :
public void onReceive(Context context, Intent intent) {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent i = new Intent(context, Schedule_Today.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi2 = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AlarmManager.INTERVAL_DAY, pi2); //Setting another notification after 1 day as soon this notification broadcast is received.
CharSequence from = "Scheduler_3";
CharSequence message = "Test Notification";
notification = new Notification(R.drawable.ic_launcher, "Attention",System.currentTimeMillis());
notification.setLatestEventInfo(context, from, message, pi);
notificationManager.notify(1, notification);
}
I want to prevent the application from being killed or at least a module of it running that can broadcast the alarmmanager at the required time so that the user receives notifications
This is not strictly possible, except by making your own version of Android in your own ROM mod.
On Android 2.1 and earlier, third-party task managers, like "Advanced Task Killer", had the ability to "force stop" an application. On Android 2.2 and higher, that ability was reserved for the OS itself, and is available to users via the "Force Stop" button on the app's screen in the list of applications in Settings.
When an app is "force stopped", among other things, all scheduled alarms are removed. In addition, on Android 3.1+, nothing of that app will ever run again, until the user manually launches one of your activities (or something else manually runs one of your components).
You are welcome to write two applications, one that is the main app and the other than ensures that, if the first one appears to have been force-stopped, the alarms are rescheduled. However, there is nothing stopping the user from force-stopping both of those applications.
Also, bear in mind that some devices, like the SONY Xperia Z, block _WAKEUP alarms in general, if the user has activated "STAMINA Mode". See this blog post for more about this.
Hence, I recommend that you redesign your application to take into account that your alarms are not guaranteed to run at all, let alone at the time you expect.
I have a Service in my application which is designed to run every 10 minutes. It basically checks up on our servers to see if everything is running properly and notifies the user of any problems. I created this application for internal use at our company.
My co-worker used the application over the long weekend and noticed that no checks were performed when the device went to sleep. I was under the impression that the Service was supposed to keep running in the background until I explicitly call stopService() in my code.
So ultimately, my goal is to have the service running until the user hits the off button in the application or kills the process.
I heard about something called WakeLock which is meant to keep the screen from turning off, which is not what I want. I then heard of another thing called a partial WakeLock, which keeps the CPU running even when the device is asleep. The latter sounds closer to what I need.
How do I acquire this WakeLock and when should I release it and are there other ways around this?
Note: This post has been updated to include the JobScheduler API of the Android Lollipop release. The following is still a viable way, but can be considered deprecated if you're targeting Android Lollipop and beyond. See the second half for the JobScheduler alternative.
One way to do recurrent tasks is this:
Create a class AlarmReceiver
public class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent myService = new Intent(context, YourService.class);
context.startService(myService);
}
}
with YourService being your service ;-)
If you require a wake lock for your Task, it is advisable to extend from WakefulBroadcastReceiver. Don't forget to add the WAKE_LOCK permission in your Manifest in this case!
Create a Pending Intent
To start your recurrent polling, execute this code in your activity:
Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
//myAlarm.putExtra("project_id", project_id); //Put Extra if needed
PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
//updateTime.setWhatever(0); //set time to start first occurence of alarm
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, recurringAlarm); //you can modify the interval of course
This code sets up an alarm and a canceable pendingIntent. The alarmManager gets the job to repeat the recurringAlarm every day (third argument), but inexact so the CPU does wake up approximately after the interval but not exactly (It lets the OS choose the optimal time, which reduces battery drain). The first time the alarm (and thus the service) is started will be the time you choose to be updateTime.
last but not least: here is how to kill the recurring alarm
Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
//myAlarm.putExtra("project_id",project_id); //put the SAME extras
PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarms.cancel(recurringAlarm);
This code creates a copy of your (probably) existing alarm and tells the alarmManager to cancel all alarms of that kind.
of course there is also something to do in the Manifest:
include these two lines
< receiver android:name=".AlarmReceiver"></receiver>
< service android:name=".YourService"></service>
inside the < application>-tag. Without it, the system does not accept the start of recurrent alarm of a service.
Starting with the Android Lollipop release, there's a new way of solving this task elegantly.
This also makes it easier to only perform an action if certain criteria such as network state are met.
// wrap your stuff in a componentName
ComponentName mServiceComponent = new ComponentName(context, MyJobService.class);
// set up conditions for the job
JobInfo task = JobInfo.Builder(mJobId, mServiceComponent)
.setPeriodic(mIntervalMillis)
.setRequiresCharging(true) // default is "false"
.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED) // Parameter may be "ANY", "NONE" (=default) or "UNMETERED"
.build();
// inform the system of the job
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(task);
You may also provide a deadline with setOverrideDeadline(maxExecutionDelayMillis).
To get rid of such a task, just call jobScheduler.cancel(mJobId); or jobScheduler.cancelAll();.
I would have recommended, if building this application from the beginning to use a server-side component (yes, would also need monitoring!) and send push notifications, polling is never a reliable solution.
From Android Documentation in doze mode following happens: (https://developer.android.com/training/monitoring-device-state/doze-standby):
The system ignores wake locks.
The system does not allow JobScheduler to run.
Android ignores AlarmManager as well unless they are in setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Network access is suspended.
So the only way is to use FCM on high priority or AlarmManager with setAndAllowWhileIdle() or setExactAndAllowWhileIdle().