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).下拉後通知欄顯示內容: