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.
Related
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.
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.
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.
I have a public class that 'extends Service' and this service is launched from an activity using startService(...). But after I use Advanced Task Killer, the service is killed and never restarted again.
I noticed that some apps like the Facebook Messenger Android App restart automatically even after killing them from Advanced Task Killer ... how are the facebook/twitter apps doing it??
Android system, or the user, may terminate a service at any time. For this reason if you want to ensure something is always running, you can schedule a periodic restart by means of AlarmManager class. The following code demonstrates how to do this.
Calendar cal = Calendar.getInstance();
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
// Start every minute
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 60*1000, pintent);
You can run this code when the user starts the app (i.e. in the oncreate of the first activity) but you have to check if it is already done, so probably it will be better if you create a broadcast receiver, than launches this code on system reboot.
If you want to restart your service automatically after being killed by another process, you can use following constants in your service,
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
You can find more information on START_STICKY & START_NON_STICKY at,
START_STICKY and START_NOT_STICKY
Also please provide your code for more specific answer.
Make onStartCommand() in your service return START_STICKY
/**
* Constant to return from {#link #onStartCommand}: if this service's
* process is killed while it is started (after returning from
* {#link #onStartCommand}), then leave it in the started state but
* don't retain this delivered intent. Later the system will try to
* re-create the service. Because it is in the started state, it will
* guarantee to call {#link #onStartCommand} after creating the new
* service instance; if there are not any pending start commands to be
* delivered to the service, it will be called with a null intent
* object, so you must take care to check for this.
*
* <p>This mode makes sense for things that will be explicitly started
* and stopped to run for arbitrary periods of time, such as a service
* performing background music playback.
*/
public static final int START_STICKY = 1;
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.