Android: keeping a background service alive (preventing process death)
I have a service that is defined as:
public class SleepAccelerometerService extends Service implements SensorEventListener
Essentially, I am making an app that monitors accelerometer activity for various reasons while the user sleeps with his or her phone/device on the bed. This is a long-running service that MUST NOT be killed during the night. Depending on how many background apps and periodic processes occur during the night, android sometimes kills off my process, thereby ending my service. Example:
10-04 03:27:41.673: INFO/ActivityManager(1269): Process com.androsz.electricsleep (pid 16223) has died.
10-04 03:27:41.681: INFO/WindowManager(1269): WIN DEATH: Window{45509f98 com.androsz.electricsleep/com.androsz.electricsleep.ui.SleepActivity paused=false}
I do not want to force the user to have 'SleepActivity' or some other activity in my app as the foreground. I can't have my service run periodically, because it is constantly intercepti开发者_开发百科ng onSensorChanged.
Any tips? source code is here: http://code.google.com/p/electricsleep/
For Android 2.0 or later you can use the startForeground()
method to start your Service in the foreground.
The documentation says the following:
A started service can use the
startForeground(int, Notification)
API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
The is primarily intended for when killing the service would be disruptive to the user, e.g. killing a music player service would stop music playing.
You'll need to supply a Notification
to the method which is displayed in the Notifications Bar in the Ongoing section.
When you bind your Service to Activity with BIND_AUTO_CREATE your service is being killed just after your Activity is Destroyed and unbound. It does not depend on how you've implemented your Services unBind method it will be still killed.
The other way is to start your Service with startService method from your Activity. This way even if your Activity is destroyed your service won't be destroyed or even paused but you have to pause/destroy it by yourself with stopSelf/stopService when appropriate.
As Dave already pointed out, you could run your Service
with foreground priority. But this practice should only be used when it's absolutely necessary, i.e. when it would cause a bad user experience if the Service got killed by Android. This is what the "foreground" really means: Your app is somehow in the foreground and the user would notice it immediately if it's killed (e.g. because it played a song or a video).
In most cases, requesting foreground priority for your Service is contraproductive!
Why is that? When Android decides to kill a Service
, it does so because it's short of resources (usually RAM). Based on the different priority classes, Android decides which running processes, and this included services, to terminate in order to free resources. This is a healthy process that you want to happen so that the user has a smooth experience. If you request foreground priority, without a good reason, just to keep your service from being killed, it will most likely cause a bad user experience. Or can you guarantee that your service stays within a minimal resource consumption and has no memory leaks?1
Android provides sticky services to mark services that should be restarted after some grace period if they got killed. This restart usually happens within a few seconds.
Image you want to write an XMPP client for Android. Should you request foreground priority for the Service
which contains your XMPP connection? Definitely no, there is absolutely no reason to do so. But you want to use START_STICKY
as return flag for your service's onStartCommand
method. So that your service is stopped when there is resource pressure and restarted once the situation is back to normal.
1: I am pretty sure that many Android apps have memory leaks. It something the casual (desktop) programmer doesn't care that much about.
I had a similar issue. On some devices after a while Android kills my service and even startForeground() does not help. And my customer does not like this issue. My solution is to use AlarmManager class to make sure that the service is running when it's necessary. I use AlarmManager to create a kind of watchdog timer. It checks from time to time if the service should be running and restart it. Also I use SharedPreferences to keep the flag whether the service should be running.
Creating/dismissing my watchdog timer:
void setServiceWatchdogTimer(boolean set, int timeout)
{
Intent intent;
PendingIntent alarmIntent;
intent = new Intent(); // forms and creates appropriate Intent and pass it to AlarmManager
intent.setAction(ACTION_WATCHDOG_OF_SERVICE);
intent.setClass(this, WatchDogServiceReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
if(set)
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, alarmIntent);
else
am.cancel(alarmIntent);
}
Receiving and processing the intent from the watchdog timer:
/** this class processes the intent and
* checks whether the service should be running
*/
public static class WatchDogServiceReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(ACTION_WATCHDOG_OF_SERVICE))
{
// check your flag and
// restart your service if it's necessary
setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
}
}
}
Indeed I use WakefulBroadcastReceiver instead of BroadcastReceiver. I gave you the code with BroadcastReceiver just to simplify it.
http://developer.android.com/reference/android/content/Context.html#BIND_ABOVE_CLIENT
public static final int BIND_ABOVE_CLIENT -- Added in API level 14
Flag for bindService(Intent, ServiceConnection, int)
: indicates that the client application binding to this service considers the service to be more important than the app itself. When set, the platform will try to have the out of memory killer kill the app before it kills the service it is bound to, though this is not guaranteed to be the case.
Other flags of the same group are: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.
Note that the meaning of BIND_AUTO_CREATE has changed in ICS, and
old applications that don't specify BIND_AUTO_CREATE
will automatically have the flags BIND_WAIVE_PRIORITY
and BIND_ADJUST_WITH_ACTIVITY
set for them.
Keep your service footprint small, this reduces the probability of Android closing your application. You can't prevent it from being killed because if you could then people could easily create persistent spyware
I'm working on an app and face issue of killing my service by on app kill. I researched on google and found that I have to make it foreground. following is the code:
public class UpdateLocationAndPrayerTimes extends Service {
Context context;
@Override
public void onCreate() {
super.onCreate();
context = this;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
StartForground();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void StartForground() {
LocationChangeDetector locationChangeDetector = new LocationChangeDetector(context);
locationChangeDetector.getLatAndLong();
Notification notification = new NotificationCompat.Builder(this)
.setOngoing(false)
.setSmallIcon(android.R.color.transparent)
//.setSmallIcon(R.drawable.picture)
.build();
startForeground(101, notification);
}
}
hops that it may helps!!!!
精彩评论