Starting new Alarm from service started by AlarmManager - android

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.

Related

Correct way to do polling in Android app

I have to develop a simple application that every 5 seconds fetch a json from a server. I know that this will drain the battery but since I don't have control on the server, this is the only solution I have at the moment, so stay with me. (It's a demo app, the final release will be totally different)
What I did:
I created an IntentService and in his onHandleIntent I do the http request and manage the response asynchronously. Reading the docs, the IntentService is preferred to the Service. At the end, as seen in other topics, I use the AlarmManager class to recreate the intentService. That's the method:
private void repeat() {
lastTrigger = System.currentTimeMillis();
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent serviceIntent = new Intent(this, StatusPollingService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, lastTrigger + UPDATE_INTERVAL, pendingIntent);
}
In my onCreate in my first Activity, I simply start the service:
serviceIntent = new Intent(BaseActivity.this, StatusPollingService.class);
startService(serviceIntent);
My issues:
When I close my application (using back button), the intentService continues to do the requests and recreates itself (as expected), so I have to kill it manually
I'd like to stop to do polling every time my app goes in background and restart when goes in foreground, to limit the battery drain
My other issues:
I implemented a class that triggers a listener when the app goes in background/foreground. I implemented the interface in my BaseActivity and in my IntentService. When the app goes in background, a boolean became false and I don't execute the repeat() method. When I go in foreground, in my method onBecameForeground I simply create the service:
serviceIntent = new Intent(BaseActivity.this, StatusPollingService.class);
#Override
public void onBecameForeground() {
startService(serviceIntent);
}
Going in background there's no problem, but going in foreground multiple intentService are created, one intentService per every Activity I have in that moment (I see it in the log).
My questions:
Is this the best way to do this job? How could I resolve these problems?
If this is the best (or the less bad) way, how can I create a single instance of the IntentService?
Thank you so much for your help
If you only need it in the foreground, then I'd not bother with the alarms. Just post intents every 5 seconds to your intent service using Handler.
Supposedly there should be only one instance of the intent service, so if you post multiple intents for processing, they will get queued and handleIntent will be called in your intent service for each intent. Note that, however, that if your service is processing intents fast enough, then it may finish (and destroyed) before you post another intent - so you'll see multiple instances of the service being created. But there will only be one instance at a time.
Edit: to expand a bit, you will need the alarms when (and if) you'll be polling the server in background, so don't through that code away ;) Handler will keep "freezing up" in background as the OS doesn't count the time while the device was sleeping for the Handler postponed execution.

Do i need to use broadcast with alarm manager?

i'm creating an alarm application, and this is the method to run the alarm :
public void startAlarm(int minuteToStart)
{
Toast.makeText(context, "Alarm Start in " + formatTime(minuteToStart), Toast.LENGTH_SHORT).show();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, minuteToStart);
Intent intent = new Intent(context, AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, idPendingIntent, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
And it run this activity after given specific time:
public class AlarmActivity extends Activity {
......
}
It works, but i see people are using BroadcastReceiver, am i doing it wrong? should i use BroadcastReceiver too? I've been searching about BroadcastReceiver but i don't get what difference it will make with my application.
Thanks.
In the general case, A--C's answer would be correct.
However, you are using RTC_WAKEUP as the alarm type. The only guarantee that we have with _WAKEUP alarms is if we use a BroadcastReceiver, then Android will ensure that the device will stay awake long enough for us to execute onReceive(). Any other type of PendingIntent -- activity or service -- has no guarantee, and it is very possible for the device to fall back asleep before the startActivity() or startService() actually occurs.
You can use AlarmManager with whatever PendingIntent is capable of (Activity, service, Receiver), though, it is usually used with Receivers - taks executing in the future usually are small and don't need an Activity to run in since the user doesn't need something popping up.
A Receiver isn't an Activity, so it does not have a UI and it has a processing time limit of about 10 seconds, so make sure to be quick. If you require a UI to be shown at a specific time, stick with an Activity, but usually this isn't the case unless it's something like an Alarm Clock app that the user has to see). If you have something like a small behind the scenes operation, go for a Receiver. The Receiver's onReceive() gets a Context passed to it so it can do anything a Context can.
Just keep in mind you will have to change the PendingIntent.getActivity() call to whatever else you decide to use if it's not going to be an Activity.
So it all depends on what you want to do.
You don't have to use a BroadcastReceiver. It's just generally frowned upon (in most cases) to steal focus and launch an Activity from the background without user interaction. There are certainly valid use cases though. If you intend to launch an Activity immediately anyway, doing that directly instead of via BroadcastReceiver is perfectly valid.

Trying to learn how to use intent and broadcast to kill my application. Why is it not dying?

I am almost finished with this game I have been making. It is a toy app and is only serving to teach me. So I call it toyapp.
I am trying to use what I learned about alarmmanager, intent, and broadcast to kill my application. I figured out how to get my alarm to go 10 seconds and then print a message to a widget. This was based on the following tutorial here.
It was my thinking that I could just call this up, warn the user I am about to kill this application and then close it out. However, it appears that the AlarmReceiver is not being called at all? My game just keeps playing.
The code I have modified is below for my toyapp.
public void timingService(Context context, Activity activity){
// get a Calendar object with current time
Calendar cal = Calendar.getInstance();
// add 5 minutes to the calendar object
cal.add(Calendar.SECOND, 5);
Intent intent = new Intent(context, AlarmReciever.class);
intent.putExtra("alarm_message", "Game will exit soon");
// In reality, you would want to have a static variable for the request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(context, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) activity.getSystemService(context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}
Now, put my Receiver code in my activity class. Which is as follows:
public class AlarmReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
try{
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
Toast.makeText(context, message, Toast.LENGTH_LONG).show(); //Give message
toyappActivity.this.finish(); //Exit the game
}catch(Exception e){
Toast.makeText(context, "There was an error somewhere", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
}//End of AlarmReciever
My inspiration for this approach was the following that I read here.
What I eventually want to do is simple. I will have an option to play the game with or without the alarm. I plan on reseting the alarmmanager with the accelerometer sensor if movement is detected. Otherwise, it will just countdown and then cancel the game.
I suspect I am not understanding intents directly, but this is my crashing point. I am so sorry if this seems stupid, but I have a rather bad cold right now and this seems like it should work to me. However, computers never lie, only our minds.
As always, you are all the best group of coders and developers. I learn so much from you all and your help is so much appreciated. Any dumb mistakes are my own, but I hope you let me off on that technicality.
Warm Regards,
GeekyOmega
The Alarm is set properly: am.set(...), it should be called only once.
But you would expect a message on you screen with:
Toast.makeText(context, message, Toast.LENGTH_LONG).show(); //Give message
The proces will refer to a :remote not sure the context what will be, as I remmeber the appContext. It seems you are trying to show a message from background and your GUI may block it. Try to remove (comment) that maeesage and let the
toyappActivity.this.finish(); //Exit the game
code run, just do a Log.d() if you want.
The AlarmManager class isn't designed for simple timeouts.
From the documentation in the link above...
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
See the Handler class to do what you want more efficiently.

How can I wake my android application at certain regular time intervals?

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.

Android AlarmManager and BroadcastReceiver running in background Service

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.

Categories

Resources