Service如果要防止尽可能不被系统杀掉,需要设置为在前台运行。
由于设置前台运行service的方法在2.0之前和2.0之后有所变化。
所以需要根据不同的版本进行区分;或者完全使用反射机制来处理,这样只要有相应的方法就可以使用,否则使用其他版本的方法。
下面是一个设置servcie前台运行的例子,参考了API中对Service的说明。
http://developer.android.com/reference/android/app/Service.html#
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import android.app.Notification;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.app.Service;
- import android.content.Context;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.Build.VERSION;
- import android.util.Log;
- public class ForegroundService extends Service {
- private static final String TAG = "ForegroundService";
- private boolean mReflectFlg = false;
- private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service
- private static final Class<?>[] mSetForegroundSignature = new Class[] {
- boolean.class};
- private static final Class<?>[] mStartForegroundSignature = new Class[] {
- int.class, Notification.class};
- private static final Class<?>[] mStopForegroundSignature = new Class[] {
- boolean.class};
- private NotificationManager mNM;
- private Method mSetForeground;
- private Method mStartForeground;
- private Method mStopForeground;
- private Object[] mSetForegroundArgs = new Object[1];
- private Object[] mStartForegroundArgs = new Object[2];
- private Object[] mStopForegroundArgs = new Object[1];
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d(TAG, "onCreate");
- mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
- try {
- mStartForeground = ForegroundService.class.getMethod("startForeground", mStartForegroundSignature);
- mStopForeground = ForegroundService.class.getMethod("stopForeground", mStopForegroundSignature);
- } catch (NoSuchMethodException e) {
- mStartForeground = mStopForeground = null;
- }
- try {
- mSetForeground = getClass().getMethod("setForeground",
- mSetForegroundSignature);
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException(
- "OS doesn't have Service.startForeground OR Service.setForeground!");
- }
- Notification.Builder builder = new Notification.Builder(this);
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, MainActivity.class), 0);
- builder.setContentIntent(contentIntent);
- builder.setSmallIcon(R.drawable.icon);
- builder.setTicker("Foreground Service Start");
- builder.setContentTitle("Foreground Service");
- builder.setContentText("Make this service run in the foreground.");
- Notification notification = builder.build();
- startForegroundCompat(NOTIFICATION_ID, notification);
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- super.onStartCommand(intent, flags, startId);
- Log.d(TAG, "onStartCommand");
- return START_STICKY;
- }
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "onDestroy");
- stopForegroundCompat(NOTIFICATION_ID);
- }
- void invokeMethod(Method method, Object[] args) {
- try {
- method.invoke(this, args);
- } catch (InvocationTargetException e) {
- // Should not happen.
- Log.w("ApiDemos", "Unable to invoke method", e);
- } catch (IllegalAccessException e) {
- // Should not happen.
- Log.w("ApiDemos", "Unable to invoke method", e);
- }
- }
- /**
- * This is a wrapper around the new startForeground method, using the older
- * APIs if it is not available.
- */
- void startForegroundCompat(int id, Notification notification) {
- if (mReflectFlg) {
- // If we have the new startForeground API, then use it.
- if (mStartForeground != null) {
- mStartForegroundArgs[0] = Integer.valueOf(id);
- mStartForegroundArgs[1] = notification;
- invokeMethod(mStartForeground, mStartForegroundArgs);
- return;
- }
- // Fall back on the old API.
- mSetForegroundArgs[0] = Boolean.TRUE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- mNM.notify(id, notification);
- } else {
- /* 还可以使用以下方法,当sdk大于等于5时,调用sdk现有的方法startForeground设置前台运行,
- * 否则调用反射取得的sdk level 5(对应Android 2.0)以下才有的旧方法setForeground设置前台运行 */
- if(VERSION.SDK_INT >= 5) {
- startForeground(id, notification);
- } else {
- // Fall back on the old API.
- mSetForegroundArgs[0] = Boolean.TRUE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- mNM.notify(id, notification);
- }
- }
- }
- /**
- * This is a wrapper around the new stopForeground method, using the older
- * APIs if it is not available.
- */
- void stopForegroundCompat(int id) {
- if (mReflectFlg) {
- // If we have the new stopForeground API, then use it.
- if (mStopForeground != null) {
- mStopForegroundArgs[0] = Boolean.TRUE;
- invokeMethod(mStopForeground, mStopForegroundArgs);
- return;
- }
- // Fall back on the old API. Note to cancel BEFORE changing the
- // foreground state, since we could be killed at that point.
- mNM.cancel(id);
- mSetForegroundArgs[0] = Boolean.FALSE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- } else {
- /* 还可以使用以下方法,当sdk大于等于5时,调用sdk现有的方法stopForeground停止前台运行,
- * 否则调用反射取得的sdk level 5(对应Android 2.0)以下才有的旧方法setForeground停止前台运行 */
- if(VERSION.SDK_INT >= 5) {
- stopForeground(true);
- } else {
- // Fall back on the old API. Note to cancel BEFORE changing the
- // foreground state, since we could be killed at that point.
- mNM.cancel(id);
- mSetForegroundArgs[0] = Boolean.FALSE;
- invokeMethod(mSetForeground, mSetForegroundArgs);
- }
- }
- }
- }
前台Service运行后的效果如图:
(1).通知栏显示内容:
(2).下拉后通知栏显示内容:
转自:http://blog.csdn.net/ameyume/article/details/9150755
如何让Android service进程变成前台进程
Android的前台ServiceService几乎都是在后台运行的,一直以来它都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service
前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息,如下图所示:
那么我们就来看一下如何才能创建一个前台Service吧,其实并不复杂,如下所示:
这里只是修改了Service中onCreate()方法的代码。可以看到,我们首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。
现在重新运行一下程序, Service就会以前台Service的模式启动了,并且在系统状态栏会弹出一个通栏图标,下拉状态栏后可以看到通知的详细内容,如下图所示:
Android:退出程序后保持Serivce开启不关闭
Android中,service的开启,默认是绑定activity的,是activity级的。
如果要实现当退出程序后,保持Service的运行,那么需要把service设置成为system级的,设置方法:
在AndroidManifest.xml中注册service时,加上属性android:process,如:
<serviceandroid:name = "com.jansun.pushnotification.PushNotificationService"android:enabled = "true"android:process = "system"/>
另外,还要在启动service时,加入FLAG_ACTIVITY_NEW_TASK标签,如:
public static void actionStart ( Context ctx ) {//System.out.println("---- Notification service started!");Intent i = new Intent(ctx, PushNotificationService .class);i.setAction(ACTION_START);i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);ctx.startService(i);}
至此,当你退出程序后,service还在系统后台正常运行,目标达成。