一般来说,一个Service默认情况下是background模式,这意味着当系统需要腾出更多的内存空间给前台应用的时候(或者系统休眠一段时间之后)就会把这些background模式的Service给杀死掉,并回收其内存空间。但是,如果把一个Service设置为foreground模式的话,就可以避免被回收这个问题。
拿音乐播放器来举个例子,一般的做法是定义一个 Service,并设置为 foreground模式,然后调用 MediaPlayer来播放音乐(播放的时候,可以在通知栏显示一个Ongoing Notification,表示正在播放音乐)。这个时候,即使系统需要为前台应用腾出内存空间,系统也不会主动终止这个 Service,当然也包括系统休眠的情况。而且,就算在【最近任务】中把所有任务都移除掉,这个 Serivce也不会被杀死。可以说, foreground模式比 background模式更不容易被回收,驻留时间更长。PS:感觉QQ就用了这个模式。
通过 Service.startForeground()和 Service.stopForeground(),可以启用或停止 foreground模式。
一般来说,只需要在 onStartCommand()里面调用 startForeground()就可以将服务设置为 foreground模式,然后再 onDestroy()里面调用 stopForeground()就切换为 background模式!
参考源码如下:
/** * 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 performing background music playback, so the user * would notice if their music stopped playing. * * 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: * * @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) { }}/** * Remove this service from foreground state, allowing it to be killed if * more memory is needed. * * @param removeNotification If true, the notification previously provided * to { @link #startForeground} will be removed. Otherwise it will * remain * until a later call removes it (or the service is destroyed). * @see #startForeground(int, Notification) */public final void stopForeground(boolean removeNotification) { try { mActivityManager.setServiceForeground(new ComponentName(this, mClassName), mToken, 0, null, removeNotification); } catch (RemoteException ex) { }}