-
Notifications
You must be signed in to change notification settings - Fork 42
Android(5): Set service foreground with notification
clarkehe edited this page Jun 24, 2016
·
5 revisions
Android的服务组件(Service)有前台(foreground)和非前台之分。要将服务设置为前台服务,只需要调用一个API就可以。
/**
* Make this service run in the foreground, supplying the ongoing
* notification to be shown to the user while in this state.
* By default services are background, meaning that if the system needs to
* kill them to reclaim more memory (such as to display a large page in a
* web browser), they can be killed without too much harm. You can set this
* flag if killing your service would be disruptive to the user, such as
* if your service is persforming background music playback, so the user
* would notice if their music stopped playing.
*
* <p>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to call the the older setForeground()
* or this modern method as appropriate:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
* foreground_compatibility}
*
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
* @param notification The Notification to be displayed.
*
* @see #stopForeground(boolean)
*/
public final void startForeground(int id, Notification notification) {
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, true);
} catch (RemoteException ex) {
}
}
将服务设置成前台后,在通知栏会有一个持续通知,同时服务所在进程的优化级也会提高。优化级高,被回收的可能性相对会小一点。在小MI手机上测试,将服务设置成前台后,服务进程的oom_adj:4 --> 1。oom_adj值越小,优先级越高。
问题:有时我们想通过将前服务设置为前台,从而提高进程的优先级,但又不想在通知栏有通知?
解决办法:对<=4.3的系统,设置一个空的Notification;对>=4.4的系统,则还要启动一个临时的服务,使用相同ID设置一个空的Notification,然后将临时服务停止。临时服务与真正的服务是一个进程。
private final static int ID = 1;
private void onSetServiceForeground(){
Log.i(TAG, "setServiceForeground");
startForeground(ID, new Notification());
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
this.startService(new Intent(this, InnerService.class));
}
}
/**
* 借助InnerService,让RecordService变成活动的前台服务,提高进程优先级,但不在通知栏显示.[黑科技,利用系统漏洞。]
*/
public static class InnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
setServiceForeground();
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void setServiceForeground(){
Log.i(TAG, "InnerService#setServiceForeground");
startForeground(ID, new Notification());
}
@Override
public void onDestroy() {
Log.i(TAG, "InnerService#onDestroy");
stopForeground(true);
super.onDestroy();
}
}
**总结:**将服务设置为前台,提高进程优化级,最终目的是为了降低进程被回收的可能(进程保活)。系统在决定进程回收顺序时,考虑了两个因素:进程优化级和进程占用内存。因此,除了提高进程优化级,还是尽量降低内存的占用。
降低内存的占用,除了有针对性优化内存外,还有一个方法时分拆进程。将需要长时保活的功能模块放到一个单独进程中,越小越好。可参考:微信Android客户端后台保活经验分享