Android AlarmManager triggered on every activity - android

I have an activity that uses AlarmManager to create an alarm that's SUPPOSED to go off every 3 minutes. It does when the app is closed, but when you open the app and as soon as you start going to different aspects of the app, the alarm onReceive() method is called on every single Activity load!
How do I stop that functionality?
I want the alarm to run ONLY EVERY 3 MINUTES
Here is my broadcast receiver:
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Testing...", Toast.LENGTH_SHORT).show();
}
Here is my setalarm method (in MainActivity onCreate)
public void startAlarmManager()
{
Intent dialogIntent = new Intent(getBaseContext(), AlarmReceiver.class);
alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
pendingIntent = PendingIntent.getBroadcast(this, 0, dialogIntent,PendingIntent.FLAG_CANCEL_CURRENT);
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), 180000, pendingIntent);
}

Your code to create the alarm is in onCreate(), so the alarm is getting created each time onCreate() is called. You could set a boolean flag when you first create the alarm, and only set the alarm when necessary. Just make sure you save that boolean to the bundle and retrieve it in onCreate() if the bundle is not null.
There is a very nice diagram of the Activity lifecycle here.
In your particular case, you should understand that onCreate() is called by the system quite often. For instance, whenever you rotate the device to change its orientation (for example, from portrait to landscape), onCreate() is called (in addition to other lifecycle methods). These methods are called in a specific order and at specific times, so you need to program 'around' that lifecycle.

Related

Android - service keep alive

have a problem with a system. I have running service, which is constantly checking the position and counting the distance and time since user start it. But after 20-25 minutes and many interactions with other applications service is being killed.
How I can prevent it?
I'm thinking to add second service which will keep my alive.
Not sure if this will work for you, but this is how i implemented it:
In my case I needed a service to keep running in the background every X minutes, and whenever it is shutdown (whether due to memory usage or main activity going to background and Android cleaning it up) it would be re-triggered again when the next time interval is reached. I had the following components and workflow:
Activity A. Main activity, the starting point of my application.
Service S. Service which I want to run in the background, do whatever it needs to do,
shutdown after completion, and start again after every X minutes.
Activity onCreate method would create a PendingIntent, passing it itself and the service S, as follows:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create an IntentSender that will launch our service, to be scheduled
// with the alarm manager.
periodicIntentSender = PendingIntent.getService(
ActivityX.this, 0, new Intent(ActivityX.this, ServiceS.class), 0);
In my activity, I have an AlarmManager implemented which will take the "periodicIntentSender" (defined above) as an argument and based on user preferences (connection_Interval) sends the intent:
// Schedule the alarm to start
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, connection_Interval, periodicIntentSender);
AlarmManager will make sure that the intent will be sent every X minutes.
My Service S keeps listening to this Intent and gets wakedup each time such an Intent is sent. As soon as the service is triggered again, its onHandleIntent method gets called.
public class ServiceS extends IntentService implements LocationListener {
.
.
/*
* (non-Javadoc)
*
* #see android.app.IntentService#onHandleIntent(android.content.Intent)
*/
#Override
protected void onHandleIntent(Intent intent) {
<WHATEVER YOU NEED TO DO>
}
}
Hope this helps.
1, minimize your service's memory usage
2, make you service foreground, for example in the service's onCreate method
#Override
public void onCreate()
{
super.onCreate();
Notification notification = new Notification(R.drawable.icon_app_small, getText(R.string.app_name),System.currentTimeMillis());
Intent notificationIntent = new Intent(this, [yourService].class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, [name string], [notification msg string], pendingIntent);
startForeground(Notification.FLAG_ONGOING_EVENT, notification);
}
But after 20-25 minutes and many interactions with other applications
service is being killed.
The most likely it's caused by too much memory usage and then automatic memory manager killed your process or long running operation as meant #AljoshaBre.
How I can prevent it?
So my first idea is to check if your Service is running in some life-cycle method for example in onResume() and if not, just you should restart your Service and execute it again.

AlarmManager Bug while Resetting/Cancelling Alarm on Date and Time Change

I want to send data to server at some regular interval. So, I am using AlarmManager for the same. It works fine but the problem is that when I cancel the Alarm on Date/Time change. At that time Alarm fires again before getting cancelled, so that makes my application worse as an extra data is sent to server with irregular interval.
Here is my BroadCastReceiver class with AlarmManager.
public class MyReceiver extends BroadcastReceiver{
AlarmManager mgr;
PendingIntent pi;
Intent intent;
public static boolean flag = false;
#Override
public void onReceive(final Context arg0, Intent arg1) {
if(arg1.getAction().equals("android.intent.action.TIME_SET")){
Log.d("MyReceiver", "Time set");
mgr = (AlarmManager) arg0.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(arg0, TestService.class);
intent.putExtra("test", "testvalue");
pi = PendingIntent.getService(arg0, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if(!flag){
mgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, 5000, pi);
flag = true;
}
else{
mgr.cancel(pi);
pi.cancel();
flag = false;
}
}
}
}
Below is the Screen Shot with Logcat output that explains that after cancelling the Alarm it fires once more time just after cancelling.
As you can see in the Logcat output black arrow shows where I changed that time to cancel the Alarm and red arrow shows that after cancelling the Alarm once again it fired just before cancelling which should not happen. So, can anyone give my idea why that is happening and what should I do to restrict Alarm getting fired again before cancelling.
NOTE:- This only happens when I tried to increase date/time say from 10:00 to 11:00, works perfect when I decrease time say 10:00 to 9:00.
Not able to see the LogCat at my end, but looking at the code, I am not sure, how is the Service which gets invoked (TestService) gets killed / stopped ? I think you would need to stop it somehow. Also, its not recommended to do long running tasks within the broadcast receiver.
Have you verified that you service stop event is occuring after the mgr.cancel(pi) is fired?
Just try with some unique code with pending intent within activity and then cancel that intent using the same code.
setting pending intent in activity
PendingIntent.getBroadcast(this, code, intent, PendingIntent.FLAG_UPDATE_CURRENT);
for stopping that broadcast receiver
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(), code, intent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
why that is happening
First Thing is that you are using Intent Action android.intent.action.TIME_SET so It does mean that Everytime any how if the System date/time gets Changed your BroadcastReceiver will ne called Automatically.
Second you have used one static boolean flag in your Receiver class.
Now what is happening is Whenever you change your System timings the flag toggles it's state from false to true and from true to false.
That is what exactly happening in your code and logcat also shows the same that everything is working as per the code written.
So according to me there is nothing Wrong happening in the code and it's output.
what should I do to restrict Alarm getting fired again before cancelling
First thing as I think, you should not use Action TIME_SET like that to toggle flag on/off as users and developers might not remember for what they are changing time either to turn FLAG On or Off,
Better way is that,
you should handle the Service yourself by an Activity and show one ToggleButton there to manage the State of the FLAG and set and cancel the PendingIntent.
OR
And If you want to do the task of your service automatically then you just simply use the AlarmManager and set your Alarm Triggering time and Interval there only once say time is currenttime and Interval is 50000 miliseconds..
so it will obviously call the service from now onwards after every 5mins, then in your App you will only require one ToggelButton to indciate the Sync to ther server is On or Off , if user Toggle it on or off then write your AlarmManager code there in your Activity only in the toggleButtontb.setOnCheckedChangeListener(listener) , I suppose this is the better way then what you are actually implementing.
I don't understand what need to set the receiver for date change if your goal is only to send the data on server in some regular interval .
change date and time of device does not mean that your alarm wont work
at that time which you already have set before those changes .Alarmmanager work on that given duration of time which is excluding from local current date and time of device .

Android - start alarm service immediately?

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.

How to keep my application service always running in android2.1?

Hi i have written reminder code in service onstart().and when user insert date-time and insert record at that time service called by startservice() function,but only service is starting when i insert record i.e i am getting reminder when it get call from my activity.but i want reminder after 3days or something so how should i keep service always on so that i can get reminder in future? or how should i make connection of service keep alive?should i called bindservice() frunction from my any activity or what?
thanks in advance---
Don't let your Service run all the time. It consumes battery and memory when not neccessary¹.
Rather schedule a PendingIntent via the AlarmManager thats starts the service at the relevant point in time to do it's work. When done, kill the service again.
In general androids services are used different then services/daemons on a "normal" computer. They have a task that they execute, then they quit (usually via Service.stopSelf()) until someone starts them again to do more work.
Here is a small example how the AlarmManager is used:
// get a calendar with the current time
Calendar cal = Calendar.getInstance();
// add 15 minutes to the calendar object
cal.add(Calendar.MINUTE, 15);
Intent intent = new Intent(ctx, YourService.class);
PendingIntent pi = PendingIntent.getService(this, 123, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi);
This launches the intent to start YourService in 15 minutes from now. There is plenty of documentation for sending intents this way, search a bit around.
¹ Which will eventually frustrate your users: "Why does this app waste my battery?" is a pretty common question
Firstly no need of service,you can useAlarManagerClass Link Alarmanger class for schedule events and show alert at specific time and date. If you want show messages after some long duration then schedule a Pending-intent via the AlarmManager thats starts the service at the relevant point in time to do it's work. When done, kill the service again as per tell by above answers . In addition you can store your data into shared preferences for permanently. You can retrieve it at any time for resheulding it on device reboot or for other purpose.
Sometimes, it may be necessary for your android app to complete a task sometime in the future. In order to do this, you must schedule an activity (can also be a service) to be run using Android’s AlarmManager. This post will show:
* How to set up a receiver for the scheduled event
* How to create an activity from this receiver
* Using the AlarmManager and the created classes to successfully receive and process a scheduled event
Creating a BroadcastReceiver
The first thing you will need is a receiver to receive the event. There are several key aspects to have for the receiver to work properly. First create a class that extends BroadcastReceiver and override and implement the necessary onReceive(Context context, Intent intent) method. The following is a basic example using a Toast message:
package com.justcallmebrian.alarmexample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import android.os.Bundle;
public class AlarmReceiver 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_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
In the previous example, we are simply just printing out the message supplied by the String passed in under the name of alarm_message. For those who are not familiar with Toast, it is basically a short and quick message given to the user. Here you can find more information on Toast.
Besides actually creating the class to receive the event, you must also declare it within AndroidManifest.xml. The following is the line that should be added before the closing of the application tag (before ).
Basically this states that the class AlarmReceiver is available and will start a private process. Once that is done, your BroadcastReceiver is ready to go.
Setting up an Event using AlarmManager
In order to receive an event, you obviously must schedule the event. There are three ways of scheduling an event (a one time event using the set method, a repeating event using the setRepeating method and finally using the setInexactRepeating). This tutorial will cover the one time alarm using the set method. For more information regarding the other events, you can view AlarmManager.
The following code snippet will get the AlarmManager and set an event to occur 5 minutes from the current time:
// get a Calendar object with current time
Calendar cal = Calendar.getInstance();
// add 5 minutes to the calendar object
cal.add(Calendar.MINUTE, 5);
Intent intent = new Intent(ctx, AlarmReceiver.class);
intent.putExtra("alarm_message", "O'Doyle Rules!");
// In reality, you would want to have a static variable for the request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
This code snippet basically obtains a new Calendar object and adds 5 minutes to it. An Intent is created with the AlarmReceiver which we created earlier. The more important piece of the code is setting the FLAG_UPDATE_CURRENT flag. Without this flag, the message being passed as an Extra will be lost and not obtained by the receiver.
With these code snippets you should be able to create and run some tasks in the BroadcastReceiver. However, sometimes you may wish to start a new activity (or service) on the alarm event. In order to do this, you would want to have the AlarmReceiver create and start the new Activity.
Starting an Activity from BroadcastReceiver
Starting an activity within a Receiver has an extra flag that is needed. We will change the previous onReceive for AlarmReceiver to get this done:
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
Intent newIntent = new Intent(context, AlarmActivity.class);
newIntent.putExtra("alarm_message", message);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
} catch (Exception e) {
Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
Now you would only have to create the new AlarmActivity as you would do any other Activity. Don’t forget to include the newly created activity in the AndroidManifest.xml file.

Passing arguments to a BroadcastReceiver through an Intent in Android

I have an application, which sets an alarm using AlarmManager, which starts another Activity when it goes off. The AlarmManager takes a PendingIntent and spawns a BroadcastReceiver class when the specified time comes. I'm wondering whether there is any way that I can pass arguments to this BroadcastReceiver through the Intent object which goes into PendingIntent?
Basically what I'd like to do is something like this:
Intent my_intent = new Intent(this, BroadcastService.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, my_intent, 0);
my_intent.putExtra("arg1", arg1);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000), pendingIntent);
and I'd like to be able to retrieve arg1 in the BroadcastReceiver's onReceive(Context, Intent) method. I figured that the local variable my_intent would be the second parameter passed on to onReceive by the PendingIntent, but apparently that's not quite right. Is it possible to pass parameters between an Activity and a BroadcastReceiver in this fashion (using Intent.putExtra()) or should I use a ContentProvider instead?
Thanks!
Iva
I had a similar problem, but I was already populating the Intent first before wrapping it in a PendingIntent. But the answer to my problem was, as pointed out above, that I needed to use the PendingIntent.FLAG_UPDATE_CURRENT flag. Once I set the flag, it worked! I hope this helps others.
-Jeff
int code=1;
Intent i2 = new Intent(StartAlarm);
i2.putExtra("_id",code);
class test extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
int i=arg1.getIntExtra("_id",-1);
}
}
I have an application, which sets an
alarm using AlarmManager, which starts
another Activity when it goes off.
That is bad form. Do not pop up activities unannounced like this without a very good reason (e.g., an incoming phone call). What if the user is in the middle of doing something, like TXTing or playing a game or trying to tap numbers for a phone menu?
Is it possible to pass parameters
between an Activity and a
BroadcastReceiver in this fashion
(using Intent.putExtra())
Yes. However, bear in mind that you will want to use PendingIntent.FLAG_UPDATE_CURRENT when you create your PendingIntent, to ensure that any new extras you supply on the Intent actually get used.
Yes, I think it is possible to pass any data of basic Java type and Serializable/Parceable types in the extras of an Intent wrapped around a PendingIntent and then retrieve them using the Intent instance passed to the onReceive of the Broadcastreceiver. Your approach looks okay to me.
What is the problem/error that you are getting? Is "arg1" instance Serializable?

Categories

Resources