Android AlarmManager and BroadcastReceiver running in background Service - android

I'm currently having a problem integrating AlarmManager and BroadcastReceiver.
Im my app, I'm running a background service that runs regardless that app is running or not. I think I get this part working fine. The background service keeps an array that changes based on user's location. However, at 8:00am everyday, I want the app to reset the array variable to default. After much looking around online, it seems like the way to do this is via AlarmManager (to initiate the task every 8:00am) and using BroadcastReceiver (to receive the alarm, and perform the task).
So basically the code goes something like this:
public class BackgroundService extends Service {
private ArrayList thisArray;
private BroadcastReceiver thisReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
setArrayToDefault();
}
}
#Override
public void onCreate(){
super.onCreate();
Calendar cal = new GregorianCalendar();
cal.add(Calendar.MINUTE, 2); //example
this.registerReceiver(thisReceiver, new IntentFilter("BackgroundService"));
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), ONE_MINUTE, "what to put here?"); //example, repeat every minute
}
private void setArrayToDefault(){
//here, the array will be changed back to default values
}
}
My main issue is on how to set the AlarmManager to call thisReceiver everytime it's set. Any idea? Is my approach correct?

Im my app, I'm running a background service that runs regardless that app is running or not.
Please don't. This is why users attack us with task killers and the Force Stop from the Manage Services screen in Settings.
My main issue is on how to set the AlarmManager to call thisReceiver everytime it's set. Any idea?
You are not registering the BroadcastReceiver, so AlarmManager will not be able to contact it.
Please please please please please please please redesign your service such that it does not have to run all of the time. Android will be killing off your service due to old age, anyway, so if you want a reliable and stable app, you need to do this redesign, anyway.

Related

Starting new Alarm from service started by AlarmManager

In my app i am using AlarmManagerto start service every week on a specific time. But in some cases instead of waiting another 7 days I need to call the service on the next day. Because of that I'm not using reapeating alarm but instead in the started service I'm creating new Alarm and set it to a specific date. Something like this:
public class AlarmService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//do something
//setting new alarm
AlarmManager alarmMng = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this,AlarmService.class);
PendingIntent alarmIntent = PendingIntent.getService(this, 0, i, 0);
Calendar c = Calendar.getInstance();
if(something) alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24,alarmIntent);
else alarmMng.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis()+1000*60*60*24*7,alarmIntent);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
Everything works fine but I wonder if this is good way to do it. Is it a good idea to create new alarm from service that was just called by one? Is it considered bad programming practice? If so how else should I handle it?
Is it considered bad programming practice?
No - this is a fine use case for creating alarm events. If you look at the documentation, use of AlarmManager is intended to send events to your app even if it is not running. Receiving those events in a Service that then schedules another alarm event is perfectly fine. The rest of my answer is intended to explain how to answer the other question you ask:
Is it a good idea to create new alarm from service that was just
called by one?
To determine if you need a Service really depends on the "do something" portion of your code more than setting the alarm. For example, you might be fine using a IntentService or even a BroadcastReceiver.
EDIT:
In other words, you will need a background process to handle this. Determining the appropriate background process (Receiver or Service) depends on how much processing needs to be done. Generally, setting an alarm all by itself could probably be handled in a Receiver but if it takes too long to process (e.g. more than 10 seconds) you will get an ANR (Application Not Responding) crash. That's when you need a service.
END EDIT..
This is a good post about services: Service vs IntentService
Specifically, the concern you should have is if your service is called multiple times, you should probably include code to cancel any previous alarms created by it, before setting a new alarm.
EDIT: Also, you are not "creating a new service" or "new alarm" each time. Services will have onStartCommand called each time an intent is sent to it (by the AlarmManager or by any other means). A new instance is not created unless it is not already instantiated.

Using TYPE_STEP_COUNTER in a background service?

I'm looking at implementing the step sensor API introduced in Android 4.4 (http://youtu.be/yv9jskPvLUc). However, I am unable to find a clear explanation on what the recommended way to monitor this in the background is? It seems like most examples only show how to do this with an activity while the app is running. I don't particularly need a high frequency of updates - I basically want to log the amount of steps the user has walked every hour to a backend service.
Should I just spin up a background service that calls registerListener on SensorManager, or is there a more elegant way?
As far as I know, there is no way around the SensorManager, but if you need the data very infrequently, you could trigger the sensor manually and get its values with a TriggerEventListener, which is a little cleaner than a SensorEventListener.
AlarmManager is typically the best option for starting an hourly timer, and it works even if your app isn't running. AlarmManager sends an Intent to a class that extends BroadcastReceiver, and that class will start your Service. The AlarmManager can be set anywhere in your app depending on your implementation.
StepCountService
SensorManager sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
Sensor stepCounter = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
sensorManager.requestTriggerSensor(listener, stepCounter);
private TriggerEventListener listener = new TriggerEventListener(){
#Override
public void onTrigger(TriggerEvent event) {
//handle step count here
}
}
MainActivity
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,AlarmManager.INTERVAL_HOUR,
AlarmManager.INTERVAL_HOUR, alarmIntent);
AlarmReceiver
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, StepCountService.class);
context.startService(service);
}
}
This is not a complete solution, but the most energy-efficient way could be to wake up your device every hour or so, start a service which quickly reads the data, then goes back to sleep.
Depending on which device level you target, using a WakefulBroadcastReceiver, as described in this answer, seems the way to go.
You need to
create the code by modifying the templates at WakefulBroadcastReceiver
add the Service and the BroadCastReceiver into the manifest.
schedule a repeating alarm somewhere in your app
If any of the points a less than clear, say so. See http://code.tutsplus.com/tutorials/android-barometer-logger-acquiring-sensor-data--mobile-10558
#TheoKanning's answer is the correct way to do this manually. Alternatively, Google Fit continuously logs this data and has an API you can use to pull it into your app.
https://developers.google.com/fit/android/get-started
https://developers.google.com/fit/android/history

Polling via an IntentService and using AlarmManager

I am just having a hard time understanding the AlarmManager system, tied in with future notifications etc. I can't seem to get the AlarmManager to set alarms at the correct frequency.
I'm also unsure where I should actually create an alarm, and what type is most suited to my needs.
Updates are based on Preferences which will be detailed below.
Launching the Service
When my application is launched, the service is called when a FragmentActivity is created. Within the onCreate(), I have the following:
Intent mServiceIntent = new Intent(this, ServiceUpdater.class);
if(startService(mServiceIntent)==null)
startService(mServiceIntent);
Lots of other stuff happens and fragments are shown ect, but this is essentially to ensure the service is running. Note, I also have it set to call the BroadcastReceiver on System startup.
ServiceUpdater.class
public class ServiceUpdater extends IntentService{
private SharedPreferences defaultPrefs;
private SharedPreferences userPrefs;
private SharedPreferences.Editor editor;
// Alarm Service
private AlarmManager alarmManager;
private PendingIntent alarmIntent;
public ServiceUpdater() {
super("MyService");
}
#Override
protected void onHandleIntent(Intent intent) {
defaultPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
userPrefs = getSharedPreferences("user", Context.MODE_PRIVATE);
long updateFrequency = (Long.parseLong(defaultPrefs.getString("updateFrequencyPref", "24")))*1000*60*60;
// in hours = 1000*60*60*'24'
long thirtySecondsAfterWake = SystemClock.elapsedRealtime() + 30*1000; // 30 seconds after the device boots
Intent intent1 = new Intent(this, UpdateReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, thirtySecondsAfterWake, updateFrequency, alarmIntent);
if(defaultPrefs.getBoolean("updatePref", true))
new Update().execute();
}
private class Update extends AsyncTask<Void, Void, Integer>{
private int newNumber;
#Override
protected Integer doInBackground(Void... params) {
newNumber= new HttpServices().getNewNumber();
return newNumber;
}
#Override
protected void onPostExecute(Integer noJobs){
if(newNumber > 0){ //userPrefs.getInt("oldNumber", 0)){
editor = userPrefs.edit();
editor.putInt("oldNumber", newNumber);
editor.commit();
if(!FragActivity.active)
new MyNotif(getApplicationContext(), "NewData");
}
}
} // end Async
} // end service class
UpdateReceiver.class
public class UpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent updater = new Intent(context, ServiceUpdater.class);
context.startService(updater);
}
}
---------------------
My guess is that when the alarm calls the Receiver, it creates a new Alarm, and then updates the old one, setting the next update time to be 30 seconds in the future; which explains why the HTTP request is happening (and I'm getting notifications every 30 seconds or so.
I want to ensure my alarm runs even when the application is not running.
My aim for this application is to do the following.
Run the App / or / On Phone Startup
Start a service that polls (e.g. Daily) a single Http Request
Regardless of the response, ensure the Polling happens again the following iteration timeframe
A notification will fire from onPostExecute based on the results of the polling
Where do I correctly set the Alarm so that it is not recreated every time the service is - but runs correctly even when the application isn't running?
Thanks for any help in advance.
but this is essentially to ensure the service is running
I have no idea why you are starting the service twice.
ServiceUpdater.class
I have no idea why you are using an AsyncTask inside an IntentService. This is bad on several levels. onHandleIntent() is already called on a background thread, and I would expect your app to flat-out crash when trying to create an AsyncTask on a background thread. Just move all the background logic into onHandleIntent() (or methods called by onHandleIntent()).
My guess is that when the alarm calls the Receiver, it creates a new Alarm, and then updates the old one, setting the next update time to be 30 seconds in the future; which explains why the HTTP request is happening (and I'm getting notifications every 30 seconds or so.
I have no idea why you are setting up a repeating alarm on every run.
Where do I correctly set the Alarm so that it is not recreated every time the service is - but runs correctly even when the application isn't running?
Your code to set up the AlarmManager schedule needs to be executed:
On the first run of your app (since you have not had an opportunity to set up the alarms yet)
After the user force-stops your app from Settings (since your previously-scheduled alarms are wiped out)
After a reboot (since your previously-scheduled alarms are wiped out)
A typical pattern for handling the first two is to keep track of when your alarm code last ran, such as in a SharedPreference. Then, either in a custom Application or in a likely entry point of your app (e.g., launcher activity), check the SharedPreference value for your last alarm run time:
If there is no value, that means it's the first run of your app, so you schedule the alarms
If there is a value, and it is significantly longer than your polling period, you assume that your app was force-stopped, and so you schedule the alarms
Otherwise, there is a plausible value, so you assume that your alarms are working just fine
Handling the reboot scenario is a matter of running through your AlarmManager scheduling logic in response to an ACTION_BOOT_COMPLETED broadcast.
Note that you are using ELAPSED_REALTIME, which means that the alarm will be delayed if the device is in sleep mode.
Also note that you are using setInexactRepeating(), which means that the alarm will go off sometime within the polling period, but not at a precise interval.

Notifications is not received in Android

I have a service which sends notifications every 2 minutes..
When the phone gets locked no new notifications are received and only when I unlock my phone I receive notifications )
Whether there is any way to change it..?
Best solution for running some task every 2 minutes is AlarmManager And do not use wakelocks except you don't need to hold device in work mode (like mp3 player for example), because it will spend battery.
UPDATE FOR ENYONE WHO TO LAZY FOR READING MANUAL
For using AlarmManager you need broadcast receiver at first.
public class ExampleReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
// this method will be called by AlarmManager. But be carefull it has timeout
// if your task need more time, you should run thread from there with wakelocks
}
}
Then you can set task to AlarmManager.
public class ExampleActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
Intent intent = new Intent(this,ExampleReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime()+INTERVAL,pendingIntent);
}
}
This example run task once after INTERVAL. And it will wakeup phone for this task. You can set repeating tasks due AlarmManager, or it possible better to set new task just from receiver
When phone is locked, the device goes to deep-sleep mode and it will not handle any wait/sleep timer related delays.
Try using AlarmManager instead for getting notification every 2 mins. Or may be hold WAKE LOCKS (though might result in battery drain and not recommended)
You might be able to accomplish your goal using the PowerManager API:
http://developer.android.com/reference/android/os/PowerManager.html
You can use this to wake the phone up briefly to handle your notification. Make sure you're familiar with how the PowerManager API works, though - it's easy to write your code in a way that drains the battery.

android service stops working after application is not in use for awhile

I have a service for my application that runs fine, but when a user is not using there phone for while like 20 minutes the service just doesnt work any more. is there something i suppose to be doing like saving a state or something, i am lost at this point. I dont see why the service doest keep running, I look in the application>running services on my phone and it still says its running. Any suggestions?
I faced the same problem few time back. Then I started to use Android Alarm Service. That solved my problem. Here is a reference link http://android-er.blogspot.com/2010/10/simple-example-of-alarm-service-using.html
If you want to keep running in the background (e.g. downloading something), you need to grab a wakelock (http://developer.android.com/reference/android/os/PowerManager.html)
Also, look at the following if you happen to do downloads in the background:
http://developer.android.com/reference/android/net/ConnectivityManager.html#getBackgroundDataSetting()
You can use Broadcast receiver instead to use like service.
And it can be called same as Service with alarm manager.
Receiver:
public class CallListReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Call List receiver called", Toast.LENGTH_LONG)
.show();
}
}
You can continuously call it using:
public void startAlert(Context context) {
Intent call_intent = new Intent(this, CallListReceiver.class);
PendingIntent pendingCallIntent = PendingIntent.getBroadcast(context,
0, call_intent, 0);
AlarmManager call_alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
call_alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), (7 * 1000), pendingCallIntent);
}
This Android's behavior that A Service has maximum life of 20 minutes. After 20 Minutes, it will be automatically killed by Android OS. But i think that there is a solution. i dont have tested it yet. The Solution is:
In your onStartCommand(), put this code at the end of this method
return START_STICKY;

Categories

Resources